首页 > 解决方案 > OpenCV 从图像和变换中检索形状轮廓

问题描述

我正在尝试使用 OpenCV 和 python 检索图像的矩形部分(文档、护照照片或类似的东西)。axis = normalize_axis_index(axis, nd) numpy.core._internal.AxisError: axis 1 is out of bounds for array of dimension 1它有效,但并非在每个图像上都有效,并且在以下代码块上失败并出现错误:

for cnt in contours:
    perimeter = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.03 * perimeter, True)
    if (len(approx) == 4 and
            cv2.isContourConvex(approx) and
            maxAreaFound < cv2.contourArea(approx) < MAX_COUNTOUR_AREA):
        maxAreaFound = cv2.contourArea(approx)
        pageContour = approx

原始图像 原来的

脱粒 脱粒

边缘 在此处输入图像描述

完整代码:

import numpy as np
import cv2


def resize(img, height=800):
    """ Resize image to given height """
    rat = height / img.shape[0]
    return cv2.resize(img, (int(rat * img.shape[1]), height))


def fourCornersSort(pts):
    diff = np.diff(pts, axis=1)
    summ = pts.sum(axis=1)

    return np.array(
        [pts[np.argmin(summ)], pts[np.argmax(diff)], pts[np.argmax(summ)],
     pts[np.argmin(diff)]])

def contourOffset(cnt, offset):
    """ Offset contour, by 5px border """
    # Matrix addition
    cnt += offset
    # if value < 0 => replace it by 0
    cnt[cnt < 0] = 0
    return cnt


image = cv2.cvtColor(cv2.imread("9.jpg"), cv2.COLOR_BGR2RGB)
img = cv2.cvtColor(resize(image), cv2.COLOR_BGR2GRAY)

img = cv2.bilateralFilter(img, 9, 75, 75)

img = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 4)

img = cv2.medianBlur(img, 11)

img = cv2.copyMakeBorder(img, 5, 5, 5, 5, cv2.BORDER_CONSTANT, value=[0, 0, 0])

edges = cv2.Canny(img, 200, 250)

im2, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
height = edges.shape[0]
width = edges.shape[1]
MAX_COUNTOUR_AREA = (width - 10) * (height - 10)
maxAreaFound = MAX_COUNTOUR_AREA * 0.5
pageContour = np.array([[5, 5], [5, height-5], [width-5, height-5],
                        [width-5, 5]])
for cnt in contours:
    perimeter = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.03 * perimeter, True)
    if (len(approx) == 4 and
            cv2.isContourConvex(approx) and
            maxAreaFound < cv2.contourArea(approx) < MAX_COUNTOUR_AREA):
        maxAreaFound = cv2.contourArea(approx)
        pageContour = approx


pageContour = fourCornersSort(pageContour[:, 0])
pageContour = contourOffset(pageContour, (-5, -5))
sPoints = pageContour.dot(image.shape[0] / 800)
height = max(np.linalg.norm(sPoints[0] - sPoints[1]),
             np.linalg.norm(sPoints[2] - sPoints[3]))
width = max(np.linalg.norm(sPoints[1] - sPoints[2]),
            np.linalg.norm(sPoints[3] - sPoints[0]))
tPoints = np.array([[0, 0],
                    [0, height],
                    [width, height],
                    [width, 0]], np.float32)

if sPoints.dtype != np.float32:
    sPoints = sPoints.astype(np.float32)

M = cv2.getPerspectiveTransform(sPoints, tPoints)
newImage = cv2.warpPerspective(image, M, (int(width), int(height)))
cv2.imwrite("resultImage.jpg", cv2.cvtColor(newImage, cv2.COLOR_BGR2RGB))

为什么会这样?

标签: pythonopencv

解决方案


import cv2

img = cv2.imread('img.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, (40, 0, 80), (255, 255, 255))  # set to the color you want to detect

blur = cv2.blur(mask, (5, 5))

ret, thresh = cv2.threshold(blur, 50, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

_, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[0]
cnts = cv2.drawContours(img, contours, -1, (0, 255, 0), 2)

cv2.imshow('blur', blur)
cv2.imshow('thresh', thresh)
cv2.imshow('cnts', cnts)

cv2.waitKey(0)

结果

您只需保存带有或不带有图像的轮廓..


推荐阅读