效果圖

原圖
仿射后

代碼如下
img =cv2.imread("test_03.png")
copy_img = img.copy()
#灰度圖
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#高斯濾波
blur = cv2.GaussianBlur(gray , (5,5),0)
#邊緣檢測
scanny = cv2.Canny(blur,75, 100)
#輪廓檢測
ctns = cv2.findContours(scanny.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[1]
cv2.drawContours(copy_img, ctns, -1, (0,0,255),3)
#排序選出最大外框
ctns = sorted(ctns, key = cv2.contourArea, reverse=True)
#擴(kuò)張成四個(gè)點(diǎn)
if len(ctns)>0:
ctns = sorted(ctns, key = cv2.contourArea, reverse=True)
for c in ctns:
peri = cv2.arcLength(c ,True)
approx = cv2.approxPolyDP(c, .02*peri, True)
if len(approx) ==4:
docCnt = approx
break;
#外框的四個(gè)點(diǎn)
(tl,tr,br,bl) = docCnt
#長寬計(jì)算,生成模板
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
maxWidth = max(int(widthA), int(widthB))
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
maxHeight = max(int(heightA), int(heightB))
dst = np.asarray([[0,0], [0, maxWidth], [maxHeight, maxWidth],[maxHeight,0]],dtype = "float32")
docCnt = np.float32(docCnt)
#計(jì)算變換矩陣
M = cv2.getPerspectiveTransform(docCnt, dst)
#利用變換矩陣計(jì)算
wrap = cv2.warpPerspective(gray, M, (maxHeight, maxWidth))
cv2.imshow("wrap",wrap)
cv2.waitKey(10000)
cv2.destroyAllWindows()