前言
在機器視覺中,對于圖像存在ROI區(qū)域傾斜現(xiàn)象,我們需要將其校正為正確的角度視角,方便下一步的布局分析與文字識別,通過透視變換可以取得比較好的裁剪效果。
一、基于輪廓提取和透射變換
? 基于輪廓提取和透射變換的矯正算法更適用于車牌、身份證、人民幣、書本、 發(fā)票一類矩形形狀而且邊界明顯的物體矯正。
算法步驟
- 圖片灰度化
- 二值化/canny邊緣檢測等操作
- 檢測輪廓,并篩選出目標(biāo)輪廓(通過橫縱比或面積去除干擾輪廓)
- 獲取圖像頂點
- 透視變換
實現(xiàn)代碼
import cv2
import numpy as np
def contour_to_rect(contour):
pts = contour.reshape(4, 2)
print(pts)
rect = np.zeros((4, 2), dtype = "float32")
# top-left point has the smallest sum
# bottom-right has the largest sum
s = pts.sum(axis = 1)
# print(s)
rect[0] = pts[np.argmin(s)]
# print(pts[np.argmin(s)])
rect[2] = pts[np.argmax(s)]
# compute the difference between the points:
# the top-right will have the minumum difference
# the bottom-left will have the maximum difference
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
# approximate the contour by a more primitive polygon shape
def approximate_contour(contour):
peri = cv2.arcLength(contour, True)
return cv2.approxPolyDP(contour, 0.032 * peri, True)
# 獲取頂點坐標(biāo)
def get_receipt_contour(contours):
# loop over the contours
for c in contours:
approx = approximate_contour(c)
# if our approximated contour has four points, we can assume it is receipt's rectangle
if len(approx) == 4:
return approx
def wrap_perspective(img, rect):
# unpack rectangle points: top left, top right, bottom right, bottom left
(tl, tr, br, bl) = rect
# compute the width of the new image
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))
# compute the height of the new image
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))
# take the maximum of the width and height values to reach
# our final dimensions
maxWidth = max(int(widthA), int(widthB))
maxHeight = max(int(heightA), int(heightB))
# destination points which will be used to map the screen to a "scanned" view
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
# calculate the perspective transform matrix
M = cv2.getPerspectiveTransform(rect, dst)
# warp the perspective to grab the screen
return cv2.warpPerspective(img, M, (maxWidth, maxHeight))
if __name__ == "__main__":
img = cv2.imread("./images/1.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 用高斯濾波處理原圖像降噪
blur = cv2.GaussianBlur(gray, (5, 5), 0)
#canny邊緣檢測(僅針對這次的輸入圖片)
edged = cv2.Canny(blur, 50, 150)
contours, h = cv2.findContours(edged.copy(), mode=cv2.RETR_EXTERNAL, method=cv2.CHAIN_APPROX_SIMPLE)
# img_contours = cv2.drawContours(img.copy(), contours, -1, (0, 0, 255), 3)
largest_contours = sorted(contours, key=cv2.contourArea, reverse=True)[:5]
# img_largest_contours = cv2.drawContours( img.copy(), largest_contours, -1, (0, 0, 255), 3)
receipt_contour = get_receipt_contour(largest_contours)
# img_receipt_contour = cv2.drawContours(img.copy(), [receipt_contour], -1, (0, 0, 255), 3)
ori_img = img.copy()
for coor in contour_to_rect(receipt_contour):
cv2.circle(ori_img, (int(coor[0]), int(coor[1])), 1, (0, 0, 255), 4)
# 進(jìn)行透視變換
scanned = wrap_perspective(img.copy(), contour_to_rect(receipt_contour))



最終效果
文章來源:http://www.zghlxwxcb.cn/news/detail-774964.html
二、基于霍夫直線探測和仿射變換
? 基于霍夫直線探測的矯正算法更適用于文本類等無明顯邊界圖像的矯正。文章來源地址http://www.zghlxwxcb.cn/news/detail-774964.html
算法步驟
- 用霍夫線變換探測出圖像中的所有直線。
- 計算出每條直線的傾斜角,求他們的平均值。
- 根據(jù)傾斜角旋轉(zhuǎn)矯正。
- 最后根據(jù)文本尺寸裁剪圖片。
實現(xiàn)代碼
import cv2
import numpy as np
img = cv2.imread("./images/4.jpg")
src = img.copy()
gray = cv2.cvtColor(src, cv2.COLOR_RGB2GRAY);
edged = cv2.Canny(src, 50, 200, apertureSize=3);
# 第5個參數(shù)就是閾值,閾值越大,檢測精度越高
plines = cv2.HoughLines(edged, 1, np.pi / 180, 200);
if plines is not None:
plines = plines.reshape(-1, 2)
print(len(plines), "lines detected")
sum_theta = 0.0
for rho, theta in plines:
# rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
sum_theta += theta
# 繪制直線
cv2.line(src, (x1, y1), (x2, y2), (0, 0, 255), 2)
# 計算平均角度
average_theta = sum_theta / len(plines)
angle = np.degrees(average_theta) - 90
# 計算旋轉(zhuǎn)中心
center = (float(img.shape[1] / 2.0), float(img.shape[0] / 2.0))
# 計算對角線長度作為旋轉(zhuǎn)后圖像的尺寸
length = int(np.sqrt(img.shape[0]**2 + img.shape[1]**2))
# 計算旋轉(zhuǎn)矩陣
M = cv2.getRotationMatrix2D(center, angle, 1)
# 進(jìn)行仿射變換并填充背景色為白色
src_rotate = cv2.warpAffine(img, M, (length, length), borderValue=(255, 255, 255))
最終效果


到了這里,關(guān)于OpenCV實戰(zhàn)之三 | 基于OpenCV實現(xiàn)圖像校正的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!