投影变换
使用opencv实现投影变换,对图片进行预处理,灰度转换,高斯模糊,canny边缘检测(找到需要投影的区域),在边缘检测的基础上获得投影区域的连通域,计算周长并使用approxPolyDP
将连续光滑曲线折线化寻找拐点,随后对指定区域使用投影变换进行投影。
# 先定义一个组合图片的函数,也可以使用matplotlib进行组图
def stackImages(scale,imgArray):
rows = len(imgArray)
cols = len(imgArray[0])
rowsAvailable = isinstance(imgArray[0], list)
width = imgArray[0][0].shape[1]
height = imgArray[0][0].shape[0]
if rowsAvailable:
for x in range ( 0, rows):
for y in range(0, cols):
if imgArray[x][y].shape[:2] == imgArray[0][0].shape [:2]:
imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)
else:
imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]), None, scale, scale)
if len(imgArray[x][y].shape) == 2: imgArray[x][y]= cv2.cvtColor( imgArray[x][y], cv2.COLOR_GRAY2BGR)
imageBlank = np.zeros((height, width, 3), np.uint8)
hor = [imageBlank]*rows
hor_con = [imageBlank]*rows
for x in range(0, rows):
hor[x] = np.hstack(imgArray[x])
ver = np.vstack(hor)
else:
for x in range(0, rows):
if imgArray[x].shape[:2] == imgArray[0].shape[:2]:
imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)
else:
imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None,scale, scale)
if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)
hor= np.hstack(imgArray)
ver = hor
return ver
import cv2
import numpy as np
# 预处理改变图片尺寸
#####################################
widthImg = 600
heightImg = 800
#####################################
img = cv2.imread('nnlrl-Learn-OpenCV-in-3-hours-master/Learn-OpenCV-in-3-hours/Resources/paper.jpg')
def preprocessing(img):
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度转换
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1) # 高斯模糊
imgCanny = cv2.Canny(imgBlur, 200, 200) # canny边缘检测
kernel = np.ones((5, 5)) # 进行膨胀和腐蚀操作,增加边缘厚度
imgDilate = cv2.dilate(imgCanny, kernel, iterations=2) # 迭代两次膨胀操作,
imgErode = cv2.erode(imgDilate, kernel, iterations=1) # 迭代依次腐蚀操作
return imgErode
cv2.imshow('image', img)
cv2.imshow('imgErode', imgErode)
image
# 获取目标区域的连通域, 计算面积寻找大于5000并且是矩形的区域
def get_contours(img):
biggest = np.array([])
maxArea = 0
contours, hierarchy = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 5000:
#cv2.drawContours(imgContour, cnt, -1, (255, 0, 0), 3)
peri = cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,0.02*peri,True)
if area > maxArea and len(approx) == 4:
biggest = approx
maxArea = area
cv2.drawContours(img_contour, biggest, -1, (255, 0, 0), 20)
return biggest
# 进行投影变换,由于返回的拐点顺序有问题,需要使用helper函数reorder对拐点进行重新排序
def get_wrapped(img, biggest):
biggest = reorder(biggest)
print(biggest.shape)
pts1 = np.float32(biggest)
pts2 = np.float32([[0, 0], [widthImg, 0], [0, heightImg], [widthImg, heightImg]])
matrix = cv2.getPerspectiveTransform(pts1, pts2)
img_output = cv2.warpPerspective(img, matrix, (widthImg, heightImg))
img_cropped = img_output[20:img_output.shape[0]-20, 20:img_output.shape[1]-20]
img_cropped = cv2.resize(img_cropped, (widthImg, heightImg))
return img_cropped
def reorder(biggest):
my_points = biggest.reshape((4, 2))
my_points_new = np.zeros((4, 1, 2), np.int32)
_sum = my_points.sum(1)
my_points_new[0] = my_points[np.argmin(_sum)]
my_points_new[3] = my_points[np.argmax(_sum)]
diff = np.diff(my_points, axis=1)
my_points_new[1] = my_points[np.argmin(diff)]
my_points_new[2] = my_points[np.argmax(diff)]
print(my_points_new)
return my_points_new
img = cv2.resize(img,(widthImg,heightImg))
imgpreprocessing = preprocessing(img)
img_contour = img.copy()
biggest = get_contours(imgpreprocessing)
img_output = get_wrapped(img, biggest)
img_stack = stackImages(0.6, ([img, imgpreprocessing], [img_contour, img_output]))
cv2.imshow('result', img_stack)
cv2.waitKey(0)
result
网友评论