opencv官网
一.插值法
1.最近邻插值
上图可看出f(p)=f(Q11),缺点可能出现明显的块状。
2.线性插值
3.双线性插值
通过线性插值确定R1和R2,最终在确定P
二.cv2.putText 图片添加文字
import cv2
img = cv2.imread('caijian.jpg')
font = cv2.FONT_HERSHEY_SIMPLEXimgzi = cv2.putText(img, '000', (50, 300), font, 1.2, (255, 255, 255), 2)
三.求凸包
import cv2
import matplotlib.pyplot as plt
import numpy as np
import scipy
from scipy.spatial import ConvexHull
##########scipy 凸包################
c = np.random.rand(5, 2)
print(c)
hull = ConvexHull(c)
# print(hull)
plt.plot(c[:,0], c[:,1], 'o')
# hull.vertices 得到凸轮廓坐标的索引值,逆时针画
hull_1=hull.vertices.tolist()#要闭合必须再回到起点[0]
print(hull_1)# hull_1.append(hull_1[0])
print(hull_1)
plt.plot(c[hull_1,0], c[hull_1,1])
plt.show()
hull_1.append(hull_1[0])这句话的作用就是要形成一个闭环。
打印结果中的4,0,2,1代表的是索引值
四.fit一条直线,可用来做轮廓旋转
path = './data/sichuan_pig_mistake_label/2018-9-14IMG_8057.JPG'
image=cv2.imread(path,cv2.IMREAD_GRAYSCALE)
img_size = cv2.resize(image, (500, 300))height, width = img_size.shape[:2]
image_thre = cv2.threshold(img_size, 127, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(image_thre, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
c = sorted(cnts, key=cv2.contourArea, reverse=True)
c = np.squeeze(c[0])
plt.plot(c[:, 0], c[:, 1])#vy/vx代表斜率 x, y是直线上的任意一点
[vx, vy, x, y] = cv2.fitLine(c, cv2.DIST_L2, 0, 0.01, 0.01)
#y=k*x+b b=-k*x1+y1
b = int((-x * vy / vx) + y)
#y=k*(cols-1)+b=(cols-1-x1)*k+y1
righty = int(((width- 1-x) * vy / vx) + y)plt.plot((0,width-1),(b,righty))
plt.show()
五.找出轮廓内的所有点
cv2.drawContours()函数
cv2.drawContours(image, contours, contourIdx, color, thickness, lineType, hierarchy, maxLevel, offset)
- 第一个参数是指明在哪幅图像上绘制轮廓;
- 第二个参数是轮廓本身,在Python中是一个list。
- 第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
path = './data/sichuan_pig_mistake_label/2018-9-14IMG_9811.JPG'
img=cv2.imread(path,cv2.IMREAD_GRAYSCALE)
# 二值化找轮廓
image_thre = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(image_thre, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = cnts[0] if imutils.is_cv2() else cnts[1]
c_ = sorted(contours, key=cv2.contourArea, reverse=True)
pig_cnt = np.squeeze(c_[0])image_h=img.shape[0]
image_w = img.shape[1]
mask = np.zeros((image_h, image_w, 3))
plt.plot(pig_cnt[:, 0], pig_cnt[:, 1])
plt.show()
dummy_mask = cv2.drawContours(mask, [pig_cnt], 0, (255, 0, 0), thickness=cv2.FILLED)
y, x = np.where(dummy_mask[:, :, 0] == 255)
inside_points = np.stack((x, y), axis=-1)
plt.plot(inside_points[:, 0], inside_points[:, 1], 'o')
plt.show()
六.cv2.fillPoly填充轮廓区域
cv2.fillPoly(img, pts, color, lineType=None, shift=None, offset=None) pts.shape:(4,2)
1.示例1
import cv2
import numpy as np
black = np.zeros((10, 10))
contour = np.array([[1, 1],[5, 1],[5, 5],[1, 5]])
img = cv2.fillPoly(black, [contour], color=(255, 255, 255))
print(img)
print(img.shape)
cv2.imwrite('./img.jpg', img)
2.示例2
import numpy as np
import cv2
import jsonjson_path = './1.json'
path ='./1.jpg'
img = cv2.imread(path).astype(np.uint8)
h, w, _ = img.shapeblack = np.zeros((h, w, 3)).astype(np.uint8)
with open(json_path) as file:json_info = json.load(file)
# print(json_info)
for shape in json_info['shapes']:label = shape['label']points = shape['points']contour = np.array(points).astype(np.int32)# print(contour.shape)# cv2.fillPoly(img, [contour], (255, 0, 0))random_b = int(np.random.randint(0, 200, 1)[0])random_g = int(np.random.randint(0, 255, 1)[0])random_r = int(np.random.randint(100, 255, 1)[0])color = (random_b, random_g, random_r)cv2.fillPoly(black, [contour], color)
dummy_mask = cv2.addWeighted(img, 1., black, 0.6, 0)
# cv2.fillConvexPoly(img, contour, 1)
cv2.imwrite('./dummy_mask.jpg', dummy_mask)
七. 图片与视频之间转换
1.测试摄像头视频
import cv2
import numpy as npcap = cv2.VideoCapture("./test.avi")
while(1):# get a frameret, frame = cap.read()# show a framecv2.imshow("capture", frame)if cv2.waitKey(100) & 0xFF == ord('q'):break
cap.release()
cv2.destroyAllWindows()
2.摄像头读完存储为本地视频
import cv2
import numpy as np#未进行亮度增强的原始视频
def test_original_video():cap = cv2.VideoCapture(0)cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)#设定宽度cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)#设定高度fourcc = cv2.VideoWriter_fourcc(*'XVID')out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))#fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')#if os.path.exists('./output.mp4'):# os.remove('./output.mp4')#out = cv2.VideoWriter('./output.mp4', fourcc, time_interval, (img_w, img_h))while cap.isOpened():frame_index = 0# get a frameisSuccess, frame = cap.read()if frame is not None:# show a frameout.write(frame) #写入本地cv2.imshow("capture", frame)#todo 写发送给后端程序if cv2.waitKey(1) & 0xFF == ord('q'):breakcap.release()out.release()cv2.destroyAllWindows()if __name__ == '__main__':test_original_video()
3.图片转视频
# 图片转视频
def jpg_video():""" 将图片合成视频. sp: 视频路径,fps: 帧率 """image_path = './image_mask_low_clear'images_list_path=[os.path.join(image_path,i) for i in os.listdir(image_path)]images_list_path=sorted(images_list_path,key=lambda x:int(x.split('/')[-1].split('.')[0]))print(images_list_path)h,w,_=cv2.imread(images_list_path[0]).shapefps=4fourcc = cv2.VideoWriter_fourcc(*'MJPG')videoWriter = cv2.VideoWriter('predict_low_clear.avi', fourcc, fps, (w, h)) # 最后一个是保存图片的尺寸for i,image_list_path in enumerate(images_list_path):frame = cv2.imread(image_list_path)videoWriter.write(frame)videoWriter.release()
4.视频转图片
# coding=utf-8
import cv2
import os
path='./data'
dirs_name_path=[os.path.join(path,i) for i in os.listdir(path)]
print(dirs_name_path)videos_src_path = "./data/videos"
# video_formats = [".MP4", ".MOV"] 我的数据集都是.mp4所以不需要进行分类判断
frames_save_path = "./data/images/"
# if not os.mkdir(frames_save_path):
# os.mkdir(frames_save_path)
time_interval = 5def video2frame(video_src_path,frame_save_path,interval):"""将视频按固定间隔读取写入图片:param video_src_path: 视频存放路径:param formats: 包含的所有视频格式:param frame_save_path: 保存路径:param frame_width: 保存帧宽:param frame_height: 保存帧高:param interval: 保存帧间隔:return: 帧图片"""videos = os.listdir(video_src_path)for each_video in videos:# print "正在读取视频:", each_videoprint("正在读取视频:", each_video) # 我的是Python3.6each_video_name = each_video[:-4]print(each_video_name)os.mkdir(frame_save_path + each_video_name)each_video_save_full_path = os.path.join(frame_save_path, each_video_name) + "/"each_video_full_path = os.path.join(video_src_path, each_video)cap = cv2.VideoCapture(each_video_full_path)frame_index = 0frame_count = 0if cap.isOpened():success = Trueelse:success = Falseprint("读取失败!")while(success):success, frame = cap.read()print("---> 正在读取第%d帧:" % frame_index, success) # 我的是Python3.6if frame_index % interval == 0 and success: # 如路径下有多个视频文件时视频最后一帧报错因此条件语句中加and success# resize_frame = cv2.resize(frame, (frame_width, frame_height), interpolation=cv2.INTER_AREA)cv2.imwrite(each_video_save_full_path + "%d.png" % frame_count, frame)frame_count += 1frame_index += 1cap.release()def main():video2frame(videos_src_path,frames_save_path,time_interval)
if __name__ == '__main__':main()
八.cv2.polylines画多边形 给定的点必须是顺时针
path = './134.jpg'img = cv2.imread(path)print(img.shape)line1 = [728, 252, 908, 215, 934, 312, 752, 355] # 四边形四个点坐标的一维数组表示,[x,y,x,y....]line2 = [741, 262, 907, 228, 923, 308, 758, 342]#debug to showline1 = np.array(line1).reshape(4, 2)line2 = np.array(line2).reshape(4, 2)cv2.polylines(img, [np.array(line1).reshape(-1, 1, 2)], True, (0, 255, 0), thickness=5)cv2.polylines(img, [np.array(line2).reshape(-1, 1, 2)], True, (0, 0, 255), thickness=5)cv2.imwrite('134_with_rect.jpg',img)
九.迪卡尔坐标和极坐标之间的转换 cv2.cartToPolar,cv2.polarToCart
(1)函数示例
#测试极坐标变换
def test_polar():# x1 = r*cos0# y1 = r*sin0x = np.array([0, 1, 2], np.float64)y = np.array([0, 1, 4], np.float64)#迪卡尔转极坐标r, theta = cv2.cartToPolar(x, y, angleInDegrees=True)print("===从迪卡尔坐标转换为极坐标===")print('r:', r)print('theta:', theta)# 极坐标转迪卡尔x1, y1 = cv2.polarToCart(r, theta, angleInDegrees=True)print("===从极坐标转换为迪卡尔坐标===")print('x1:', x1)print('y1:', y1)
(2)运用
#coding:utf-8
import cv2
import numpy as npdef polar(img, center, r, theta=(0, 360), rstep=1.0, thetastep = 360.0/(180*8)):# 图像灰度处理gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 得到距离的最小、最大范围minr, maxr = rprint('r:', r)#角度的最小范围mintheta, maxtheta = thetaprint('mintheta, maxtheta', mintheta, maxtheta)# 输出图像的高、宽H = int((maxr-minr)/rstep)+1W = int((maxtheta-mintheta)/thetastep)+1O = 125 * np.ones((H, W), gray.dtype)print('H:', H)print('W:', W)# print('O.shape:', O.shape)# 极坐标变换r = np.linspace(minr, maxr, H)# print('r.shape:', r.shape)r = np.tile(r, (W, 1))# print('r.shape:', r.shape)r = np.transpose(r)print('r.shape:', r.shape)theta = np.linspace(mintheta, maxtheta, W)theta = np.tile(theta, (H, 1))x, y = cv2.polarToCart(r, theta, angleInDegrees=True)print('theta.shape:', theta.shape)# 最近邻插值for i in range(H):for j in range(W):px = int(round(x[i][j]) + cx)py = int(round(y[i][j]) + cy)if((px>=0 and px<=w-1)and (py>=0 and py<=h-1)):O[i][j] = gray[py][px]return Oif __name__ == '__main__':print("---------------Hello python ------------")filename = ("disk.png")img = cv2.imread(filename)# 图像的宽、高h, w = img.shape[:2]# 极坐标中心cx, cy = w/2, h/2# 标出图像中心点cv2.circle(img, (int(cx), int(cy)), 10, (255, 0, 0), 3)out = polar(img, (cx, cy), (0, w/2))out = out[::-1, ...]cv2.imwrite('out.jpg', out)
变为
十.利用cv2.inRange选择ROI hsv截图ROI
src = cv2.imread('./flower.png')# 生成mask区域hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)mask = cv2.inRange(hsv, (156, 43, 46), (180, 255, 255))print('mask.shape:', mask.shape)cv2.imwrite('mask.jpg', mask)mask = np.concatenate((np.expand_dims(mask,-1),np.expand_dims(mask,-1),np.expand_dims(mask,-1)),axis=-1)# 提取ROI区域,根据mask# result = cv2.bitwise_and(src, src, mask=mask)result = mask/255*srccv2.imwrite('result.jpg', result)
十一.cv2.bitwise_and 用来做与操作,可以过滤噪声, cv2.getStructuringElement定义卷积核形式
1.案例1
img = cv2.imread('./table_crop_bin_.jpg')img_bin = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)mask_= cv2.imread('./mask.jpg')mask = cv2.cvtColor(mask_, cv2.COLOR_BGR2GRAY)mask[mask < 127] = 0img_bin_ = cv2.bitwise_and(img_bin, img_bin, mask=mask)cv2.imwrite('./img_bin_after_mask.jpg',img_bin_)
img_bin:
mask:
after_mask:
2.案例2 cv2.getStructuringElement定义十字卷积核,再膨胀这样只对线变粗
img = cv2.imread('./table_crop.jpg')
cv_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
img_bin = cv2.adaptiveThreshold(cv_img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
img_bin = 255 - img_bin # Invert the image# 二次消除小轮廓
# image, contours, hierarchy = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)#opencv3
contours, _ = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)#opencv4
mask = np.ones(img.shape[:2], dtype="uint8") * 255
th_w = img_bin.shape[1]/30
th_h = img_bin.shape[0]/30
for c in contours:x, y, w, h = cv2.boundingRect(c) #第一遍根据长宽删选if w < th_w and h < th_h:cv2.drawContours(mask, [c], -1, 0, -1)
# cv2.imwrite('./mask.jpg', mask)
img_bin = cv2.bitwise_and(img_bin, img_bin, mask=mask)img_bin_ = ~img_bin
cv2.imwrite('./img_bin_no_noise.jpg', img_bin_)kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
img_bin = cv2.dilate(img_bin, kernel, iterations=1)
cv2.imwrite('./img_bin_dilate.jpg', img_bin)
3.案例3用来去除背景
import cv2
import numpy as np
path = './test_threshold.png'
img = cv2.imread(path)
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
#自适应二值化
threshold = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,25,15)
# cv2.imwrite('./threshold.jpg', threshold)
#形态学操作进行膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
mask = cv2.dilate(threshold, kernel)
# cv2.imwrite('./mask.jpg', mask)
#背景为白色的黑色字
mask1 = cv2.bitwise_not(mask)
# cv2.imwrite('./mask1.jpg', mask1)
#扣出文字,此时背景为黑色
mask_img = cv2.bitwise_and(gray, mask)
# cv2.imwrite('./mask_img.jpg', mask_img)
#融合得出去除背景的图
fin_mask_img = cv2.add(mask_img, mask1)
cv2.imwrite('./fin_mask_img.jpg', fin_mask_img)
原图 去完背景图
十二.一些非线性变换,主要用于图像增强
1.图像灰度非线性变换:DB=DA×DA/255,灰色会变成黑色
#coding:utf-8
import numpy as np
import cv2
import matplotlib.pyplot as plt#原始图像的灰度值按照DB = DA×DA / 255的公式进行非线性变换,使灰色的变成黑色
def non_linear_transform():path = './test_gamma.png'img = cv2.imread(path)# print('==img.shape:', img.shape)gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)h, w = gray_img.shape# cv2.imwrite('./gray_img.jpg', gray_img)temp_img = gray_img.copy().astype(np.float32)print(temp_img.dtype)# cv2.imwrite('./temp_img.jpg', temp_img)out_img = np.clip((temp_img*temp_img)/255, 0, 255)cv2.imwrite('./out_img.jpg', out_img)
2.图像灰度对数变换
公式:
由于对数曲线在像素值较低的区域斜率大,在像素值较高的区域斜率较小,所以图像经过对数变换后,较暗区域的对比度将有所提升。可用于增强图像的暗部细节.
#图像灰度的对数变换--Db=c*log(1+Da)
#对数变换对于整体对比度偏低并且灰度值偏低的图像增强效果较好。
def log_transform():x = np.arange(0, 256, 0.01)c = 1.y = c*np.log(1+x)#以e为底plt.plot(x, y, 'r', linewidth='1')plt.rcParams['font.sans-serif'] = ['SimHei'] #正常显示中文标签plt.title(u'对数变换')plt.xlim(0, 255)plt.ylim(0, 6)plt.show()path = './log_tr.png'img = cv2.imread(path).astype(np.float32)c = 42.out = c * np.log(1 + img) # 以e为底out = np.clip(out+0.5, 0, 255).astype(np.uint8)cv2.imwrite('./out_log.jpg', out)
3.图像灰度伽玛变换
公式:
伽马变换对于图像对比度偏低,并且整体亮度值偏高(或由于相机过曝)情况下的图像增强效果明显
#gamma变换Db=c*Da^gamma
#当gamma>1时,会拉伸图像中灰度级较高的区域,压缩灰度级较低的部分。
#当gamma<1时,会拉伸图像中灰度级较低的区域,压缩灰度级较高的部分。
#当gamma=1时,该灰度变换是线性的,此时通过线性方式改变原图像。
#适用于解决曝光过度的问题
def gamma_transform():path = './gamma_test.png'img = cv2.imread(path).astype(np.float32)c = 0.00000005gamma = 4.0out = c*img**gammaout = np.clip(out, 0, 255)cv2.imwrite('./out_gamma.jpg', out)
十三-1:cv2.warpAffine()仿射变换函数
例1.可实现旋转,平移,缩放;变换后的平行线依旧平行,用于图像预处理
import cv2img = cv2.imread('./20210829110603899.png', 0)
h, w = img.shape
new_h = 1000
new_w = 600
scale = min(new_h / h, new_w / w)
print(new_h / h, new_w / w)
factor = np.array([[scale, 0, 0],[0, scale, 0]])
new_img = cv2.warpAffine(img, factor, (new_w, new_h), borderValue=127)
print(new_img.shape)
cv2.imwrite('./new_img1.jpg', new_img)factor = np.array([[scale, 0, new_w / 2 - scale * w / 2],[0, scale, new_h / 2 - scale * h / 2]])
new_img = cv2.warpAffine(img, factor, (new_w, new_h), borderValue=127)
print(new_img.shape)
cv2.imwrite('./new_img2.jpg', new_img)
例2.通过原始点与目标点计算仿射矩阵,变换图像与关键点
import numpy as np
import cv2def get_affine_transform(center,scale,rot,output_size,shift=(0., 0.),inv=False):"""Get the affine transform matrix, given the center/scale/rot/output_size.Args:center (np.ndarray[2, ]): Center of the bounding box (x, y).scale (np.ndarray[2, ]): Scale of the bounding boxwrt [width, height].rot (float): Rotation angle (degree).output_size (np.ndarray[2, ] | list(2,)): Size of thedestination heatmaps.shift (0-100%): Shift translation ratio wrt the width/height.Default (0., 0.).inv (bool): Option to inverse the affine transform direction.(inv=False: src->dst or inv=True: dst->src)Returns:np.ndarray: The transform matrix."""assert len(center) == 2assert len(scale) == 2assert len(output_size) == 2assert len(shift) == 2# pixel_std is 200.scale_tmp = scale * 200.0shift = np.array(shift)src_w = scale_tmp[0]dst_w = output_size[0]dst_h = output_size[1]rot_rad = np.pi * rot / 180src_dir = rotate_point([0., src_w * -0.5], rot_rad)dst_dir = np.array([0., dst_w * -0.5])print('=center:', center)print('==scale_tmp:', scale_tmp)print('==:shift:', shift)print('=src_dir:', src_dir)src = np.zeros((3, 2), dtype=np.float32)src[0, :] = center + scale_tmp * shiftsrc[1, :] = center + src_dir + scale_tmp * shiftsrc[2, :] = _get_3rd_point(src[0, :], src[1, :])print('===src:', src)dst = np.zeros((3, 2), dtype=np.float32)dst[0, :] = [dst_w * 0.5, dst_h * 0.5]dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5]) + dst_dirdst[2, :] = _get_3rd_point(dst[0, :], dst[1, :])print('===dst:', dst)if inv:trans = cv2.getAffineTransform(np.float32(dst), np.float32(src))else:trans = cv2.getAffineTransform(np.float32(src), np.float32(dst))return trans, src, dstdef _get_3rd_point(a, b):"""To calculate the affine matrix, three pairs of points are required. Thisfunction is used to get the 3rd point, given 2D points a & b.The 3rd point is defined by rotating vector `a - b` by 90 degreesanticlockwise, using b as the rotation center.Args:a (np.ndarray): point(x,y)b (np.ndarray): point(x,y)Returns:np.ndarray: The 3rd point."""assert len(a) == 2assert len(b) == 2direction = a - bthird_pt = b + np.array([-direction[1], direction[0]], dtype=np.float32)return third_ptdef rotate_point(pt, angle_rad):"""Rotate a point by an angle.Args:pt (list[float]): 2 dimensional point to be rotatedangle_rad (float): rotation angle by radianReturns:list[float]: Rotated point."""assert len(pt) == 2sn, cs = np.sin(angle_rad), np.cos(angle_rad)new_x = pt[0] * cs - pt[1] * snnew_y = pt[0] * sn + pt[1] * csrotated_pt = [new_x, new_y]return rotated_ptdef affine_transform(pt, trans_mat):"""Apply an affine transformation to the points.Args:pt (np.ndarray): a 2 dimensional point to be transformedtrans_mat (np.ndarray): 2x3 matrix of an affine transformReturns:np.ndarray: Transformed points."""assert len(pt) == 2new_pt = np.array(trans_mat) @ np.array([pt[0], pt[1], 1.])return new_ptc = np.array([176.23245, 235.00899], dtype=np.float)
s = np.array([1.676609, 1.676609], dtype=np.float32)
r = 0
image_size = [256, 256]
img1 = cv2.imread('./hand_img.jpg')trans, src, dst = get_affine_transform(c, s, r, image_size)#获取仿射变换矩阵# assert 1 == 0
#对原始图片进行仿射变换,获取需要的256*256图片
img2 = cv2.warpAffine(img1,trans, (int(image_size[0]), int(image_size[1])),flags=cv2.INTER_LINEAR)joint_3d = np.array([[ 179.5004 , 155.19913 , -28.959717 ],[ 204.43983 , 181.01262 , -27.860962 ],[ 238.99097 , 203.22014 , -24.98816 ],[ 258.56006 , 247.28287 , -22.415161 ],[ 82.02937 , 208.90874 , 15.491821 ],[ 108.736206 , 211.6331 , 12.446289 ],[ 138.15198 , 214.90436 , 12.52124 ],[ 187.65051 , 224.30232 , 5.1589355],[ 64.458534 , 238.55043 , 22.159302 ],[ 92.78469 , 239.35489 , 19.358276 ],[ 129.30128 , 241.59935 , 21.450684 ],[ 184.5111 , 248.95364 , 16.177368 ],[ 74.88563 , 269.69592 , 24.958252 ],[ 102.517715 , 269.61853 , 22.434326 ],[ 137.18251 , 269.18402 , 24.199707 ],[ 186.39644 , 272.3858 , 18.314575 ],[ 109.839554 , 314.81885 , 34.159058 ],[ 132.8085 , 308.8698 , 28.636108 ],[ 156.04227 , 302.9549 , 25.372803 ],[ 193.64702 , 295.3736 , 17.579102 ],[ 288.0064 , 272.3743 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ],[-644.62415 , 38.12097 , 0. ]], dtype=np.float32)print('==trans:', trans)
for point in src:cv2.circle(img1, tuple(point.astype(np.int)), radius=2, color=(0, 0, 255), thickness=2)
for point in joint_3d:cv2.circle(img1, tuple(point[:2].astype(np.int)), radius=2, color=(255, 0, 0), thickness=2)
cv2.imwrite('./hand_img_draw.jpg', img1)for i in range(len(joint_3d)):joint_3d[i, 0:2] = affine_transform(joint_3d[i, 0:2], trans)print('==trans:', trans)
for point in dst:cv2.circle(img2, tuple(point.astype(np.int)), radius=2, color=(0, 0, 255), thickness=2)
for point in joint_3d:cv2.circle(img2, tuple(point[:2].astype(np.int)), radius=2, color=(255, 0, 0), thickness=2)
cv2.imwrite('./hand_img_affine_draw.jpg', img2)
十三-2.透视变换cv2.getPerspectiveTransform
可保持直线不变形,但是平行线可能不再平行
点的还原
pts1 = np.float32([[0, 1], [2, 0], [3, 1], [1, 2]])
pts2 = np.float32([[0, 0], [4, 0], [4, 2], [0, 2]])M = cv2.getPerspectiveTransform(pts1, pts2)
print('===放射矩阵为M:', M)ones = np.ones((4, 1))
tmp = np.concatenate([pts2, ones], axis=-1)
print('==tmp:', tmp)
I = np.matrix(M).I#求逆矩阵
pts1_reduction = np.matmul(I, tmp.transpose(1, 0)).transpose(1, 0)
print('==pts1_reduction:', pts1_reduction)
print(pts1_reduction[:, :2])
根据box的长宽对图片进行不同的透视变换:
def crop_image_by_bbox(self, image, box):w = (int)(np.linalg.norm(box[0] - box[1]))h = (int)(np.linalg.norm(box[0] - box[3]))width = wheight = hif h > w * 1.5:width = hheight = wM = cv2.getPerspectiveTransform(np.float32(box),np.float32(np.array([[width, 0], [width, height], [0, height], [0, 0]])))else:M = cv2.getPerspectiveTransform(np.float32(box),np.float32(np.array([[0, 0], [width, 0], [width, height], [0, height]])))warped = cv2.warpPerspective(image, M, (width, height))return warped, M#例子:
box = np.array([[1, 2],[3, 4],[5, 6],[7, 8]])
十四.cv2.applyColorMap生成伪彩色
path = './bgr_region_scores.jpg'
img = cv2.imread(path)
img_color = cv2.applyColorMap(np.uint8(img), cv2.COLORMAP_JET)
cv2.imwrite('./img_color.jpg', img_color)
十五.裁剪斜矩形框
方式1:思路:通过计算box的旋转角度,旋转图像和计算旋转后的box在进行裁剪
#coding:utf-8
import cv2
from math import *
import numpy as np
import time, math
import os
import re'''旋转图像并剪裁'''
def rotate(img, points, rotateImagePath, clipImagePath):pt1, pt2, pt3, pt4 = pointsprint('==旋转前pt1,pt2,pt3,pt4:', pt1, pt2, pt3, pt4)withRect = math.sqrt((pt4[0] - pt1[0]) ** 2 + (pt4[1] - pt1[1]) ** 2) # 矩形框的宽度heightRect = math.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)print('==withRect, heightRect:', withRect, heightRect)angle = acos((pt4[0] - pt1[0]) / withRect) * (180 / math.pi) # 矩形框旋转角度print('==angle:', angle)if pt4[1] > pt1[1]:print("相比原图水平线顺时针旋转")else:print("相比原图水平线逆时针旋转")angle = -angleheight = img.shape[0] # 原始图像高度width = img.shape[1] # 原始图像宽度rotateMat = cv2.getRotationMatrix2D((width / 2, height / 2), angle, 1) # 按angle角度旋转图像heightNew = int(width * fabs(sin(radians(angle))) + height * fabs(cos(radians(angle))))widthNew = int(height * fabs(sin(radians(angle))) + width * fabs(cos(radians(angle))))rotateMat[0, 2] += (widthNew - width) / 2rotateMat[1, 2] += (heightNew - height) / 2imgRotation = cv2.warpAffine(img, rotateMat, (widthNew, heightNew), borderValue=(255, 255, 255))print('==旋转矩阵:', rotateMat.shape)print('==旋转前pt1,pt2,pt3,pt4:', pt1, pt2, pt3, pt4)# 旋转后图像的四点坐标# pt1_rotate = np.dot(rotateMat, np.array([[pt1[0]], [pt1[1]], [1]]))# pt2_rotate = np.dot(rotateMat, np.array([[pt2[0]], [pt2[1]], [1]]))# pt3_rotate = np.dot(rotateMat, np.array([[pt3[0]], [pt3[1]], [1]]))# pt4_rotate = np.dot(rotateMat, np.array([[pt4[0]], [pt4[1]], [1]]))# print('==pt1_rotate:', pt1_rotate)# print('==pt2_rotate:', pt2_rotate)# print('==pt3_rotate', pt3_rotate)# print('==pt4_rotate:', pt4_rotate)[[pt1[0]], [pt1[1]]] = np.dot(rotateMat, np.array([[pt1[0]], [pt1[1]], [1]]))[[pt2[0]], [pt2[1]]] = np.dot(rotateMat, np.array([[pt2[0]], [pt2[1]], [1]]))[[pt3[0]], [pt3[1]]] = np.dot(rotateMat, np.array([[pt3[0]], [pt3[1]], [1]]))[[pt4[0]], [pt4[1]]] = np.dot(rotateMat, np.array([[pt4[0]], [pt4[1]], [1]]))print('==旋转后pt1,pt2,pt3,pt4:', pt1, pt2, pt3, pt4)imgclip = imgRotation[int(pt1[1]):int(pt3[1]), int(pt1[0]):int(pt3[0])]cv2.imwrite(clipImagePath, imgclip) # 裁减得到的旋转矩形框cv2.imwrite(rotateImagePath, imgRotation)return imgRotation#校正逆时针的四个点 从左上角开始
def cal_stand_points(points):rect = np.zeros((4, 2))s = np.sum(points, axis=1)rect[0] = points[np.argmin(s)]rect[2] = points[np.argmax(s)]# the top-right point will have the smallest difference,# whereas the bottom-left will have the largest differenced = np.diff(points, axis=1)rect[3] = points[np.argmin(d)]rect[1] = points[np.argmax(d)]return rect
def main():points = np.array([[137, 32],[408, 250],[319, 365],[46, 137]])points = cal_stand_points(points)print('===points:', points)img = cv2.imread('./D8_1_LowAngleLight111.jpg')rotate(img, points, rotateImagePath='./out.jpg', clipImagePath='./out_clip.jpg')if __name__ == "__main__":main()
原图
旋转后原图 裁剪图
方式2:直接做透视变换
import cv2
import numpy as npdef main():img = cv2.imread("./1.jpg")# points for test.jpgcnt = np.array([[408, 250],[137, 32],[319, 365],[46, 137]])rect = cv2.minAreaRect(cnt)print("rect: {}".format(rect))# the order of the box points: bottom left, top left, top right,# bottom rightbox = cv2.boxPoints(rect)box = np.int0(box)print("bounding box: {}".format(box))# get width and height of the detected rectangleshort_side = int(rect[1][0])long_side = int(rect[1][1])src_pts = box.astype("float32")# coordinate of the points in box points after the rectangle has been# straighteneddst_pts = np.array([[long_side-1, short_side-1],[0, short_side - 1],[0, 0],[long_side-1, 0],], dtype="float32")print(src_pts, dst_pts)# the perspective transformation matrixM = cv2.getPerspectiveTransform(src_pts, dst_pts)# directly warp the rotated rectangle to get the straightened rectanglewarped = cv2.warpPerspective(img, M, (long_side, short_side))# return warpedcv2.imwrite("crop_img.jpg", warped)# cv2.waitKey(0)if __name__ == "__main__":main()
十六.获取向外扩充的polygon
from shapely.geometry import Polygon
import pyclipper
import numpy as np#获取每条边向外扩充后的polygon
def unclip(box, unclip_ratio=1.5):poly = Polygon(box)#每条边向外扩充的长度 面积 周长distance = poly.area * unclip_ratio / poly.lengthoffset = pyclipper.PyclipperOffset()offset.AddPath(box, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)expanded = np.array(offset.Execute(distance))return expandedimg = np.zeros((700, 700, 3))
points = np.array([[597.40393, 147.45522],[681.53076, 136.4222],[682.52625, 144.01295],[598.3994, 155.04597]]).astype(np.int)
expand_points = unclip(points)
print('==expand_points.shape:', expand_points.shape)
print('==expand_points:', expand_points)cv2.polylines(img, [np.array(points).reshape(-1, 1, 2)], True, (255, 255, 255), thickness=1)
cv2.polylines(img, [np.array(expand_points).reshape(-1, 1, 2)], True, (255, 255, 255), thickness=3)cv2.imwrite('./img_rect.jpg', img)
十七.坐标和图片一起旋转90,180
import numpy as np
#得到左上角开始的顺时针四个点
def cal_stand_points(point):s = np.sum(point, axis=1)left_top_index = np.argmin(s)# right_bottom_index = np.argmax(s)rect = np.roll(point, 4-left_top_index, axis=0)return rect.reshape(-1,).tolist()#文字框旋转90度
def rotate_90(box, w):new_box = np.zeros_like(box)new_box[0::2] = box[1::2]new_box[1::2] = w - box[0::2]new_box = np.roll(new_box, 6)return new_box#文字框旋转180度
def rotate_180(box, w, h):new_box = np.zeros_like(box)new_box[0::2] = w - box[0::2]new_box[1::2] = h - box[1::2]new_box = np.roll(new_box, 6)new_box = cal_stand_points(np.array(new_box).reshape(-1, 2))return new_boximg = np.zeros((80,40))
img_h, img_w = img.shapebox = np.array([0, 0, 20, 0, 20, 20, 0, 20])cv2.polylines(img, [np.array(box).reshape(-1, 1, 2)], True, (255, 255, 255), thickness=2)
cv2.imwrite('./img_ori.jpg', img)new_box = rotate_90(box, img_w)
copy_img = np.rot90(img.copy())
print('=new_box:', new_box)
cv2.polylines(copy_img, [np.array(new_box).reshape(-1, 1, 2)], True, (255, 255, 255), thickness=2)
cv2.imwrite('./img_rot90.jpg', copy_img)copy_img2 = np.rot90(np.rot90(img.copy()))
box = np.array([0, 0, 0, 20, 20, 20, 0, 20])
new_box = rotate_180(box, img_w, img_h)
print('=new_box:', new_box)
cv2.polylines(copy_img2, [np.array(new_box).reshape(-1, 1, 2)], True, (255, 255, 255), thickness=2)
cv2.imwrite('./img_rot180.jpg', copy_img2)