【问题标题】:Error : Invalid number of channels in input image: 'VScn::contains(scn)' using opencv?错误:输入图像中的通道数无效:'VScn::contains(scn)' 使用 opencv?
【发布时间】:2021-09-12 14:12:15
【问题描述】:

我正在尝试取消剪切图像,就像 cam 扫描仪所做的那样,它适用于某些图像,如果我给出任何随机图像它不起作用,名为 new_image.jpeg 的图像不起作用,图像命名为 1111。 jpeg 正在工作。虽然图片完全一样。

代码:

import numpy as np
import cv2
import re
from matplotlib import pyplot as plt
import warnings
warnings.filterwarnings('ignore')


# ## **Use Gaussian Blurring combined with Adaptive Threshold** 

def blur_and_threshold(gray):
    gray = cv2.GaussianBlur(gray,(3,3),2)
    threshold = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,2)
    threshold = cv2.fastNlMeansDenoising(threshold, 11, 31, 9)
    return threshold


# ## **Find the Biggest Contour** 

# **Note: We made sure the minimum contour is bigger than 1/10 size of the whole picture. This helps in removing very small contours (noise) from our dataset**


def biggest_contour(contours,min_area):
    biggest = None
    max_area = 0
    biggest_n=0
    approx_contour=None
    for n,i in enumerate(contours):
            area = cv2.contourArea(i)
            if area > min_area/10:
                    peri = cv2.arcLength(i,True)
                    approx = cv2.approxPolyDP(i,0.02*peri,True)
                    if area > max_area and len(approx)==4:
                            biggest = approx
                            max_area = area
                            biggest_n=n
                            approx_contour=approx                                                                         
    return biggest_n,approx_contour


def order_points(pts):
    # initialzie a list of coordinates that will be ordered
    # such that the first entry in the list is the top-left,
    # the second entry is the top-right, the third is the
    # bottom-right, and the fourth is the bottom-left
    pts=pts.reshape(4,2)
    rect = np.zeros((4, 2), dtype = "float32")

    # the top-left point will have the smallest sum, whereas
    # the bottom-right point will have the largest sum
    s = pts.sum(axis = 1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]

    # now, compute the difference between the points, the
    # top-right point will have the smallest difference,
    # whereas the bottom-left will have the largest difference
    diff = np.diff(pts, axis = 1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]

    # return the ordered coordinates
    return rect


### Find the exact (x,y) coordinates of the biggest contour and crop it out
def four_point_transform(image, pts):
    # obtain a consistent order of the points and unpack them
    # individually
    rect = order_points(pts)
    (tl, tr, br, bl) = rect

    # compute the width of the new image, which will be the
    # maximum distance between bottom-right and bottom-left
    # x-coordiates or the top-right and top-left x-coordinates
    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))
   

    # compute the height of the new image, which will be the
    # maximum distance between the top-right and bottom-right
    # y-coordinates or the top-left and bottom-left y-coordinates
    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))

    # now that we have the dimensions of the new image, construct
    # the set of destination points to obtain a "birds eye view",
    # (i.e. top-down view) of the image, again specifying points
    # in the top-left, top-right, bottom-right, and bottom-left
    # order
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype = "float32")

    # compute the perspective transform matrix and then apply it
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # return the warped image
    return warped


# # Transformation the image

# **1. Convert the image to grayscale**

# **2. Remove noise and smoothen out the image by applying blurring and thresholding techniques**

# **3. Use Canny Edge Detection to find the edges**

# **4. Find the biggest contour and crop it out**


def transformation(image):
    image=image.copy()  
    height, width, channels = image.shape
    gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    image_size=gray.size
  
    threshold=blur_and_threshold(gray)
    # We need two threshold values, minVal and maxVal. Any edges with intensity gradient more than maxVal 
    # are sure to be edges and those below minVal are sure to be non-edges, so discarded. 
    #  Those who lie between these two thresholds are classified edges or non-edges based on their connectivity.
    # If they are connected to "sure-edge" pixels, they are considered to be part of edges. 
    #  Otherwise, they are also discarded
    edges = cv2.Canny(threshold,50,150,apertureSize = 7)
    contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    simplified_contours = []


    for cnt in contours:
        hull = cv2.convexHull(cnt)
        simplified_contours.append(cv2.approxPolyDP(hull,
                                0.001*cv2.arcLength(hull,True),True))
    simplified_contours = np.array(simplified_contours)
    biggest_n,approx_contour = biggest_contour(simplified_contours,image_size)

    threshold = cv2.drawContours(image, simplified_contours ,biggest_n, (0,255,0), 1)

    dst = 0
    if approx_contour is not None and len(approx_contour)==4:
        approx_contour=np.float32(approx_contour)
        dst=four_point_transform(threshold,approx_contour)
    croppedImage = dst
    return croppedImage


# **Increase the brightness of the image by playing with the "V" value (from HSV)**

def increase_brightness(img, value=30):
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    h, s, v = cv2.split(hsv)
    lim = 255 - value
    v[v > lim] = 255
    v[v <= lim] += value
    final_hsv = cv2.merge((h, s, v))
    img = cv2.cvtColor(final_hsv, cv2.COLOR_HSV2BGR)
    return img  


# **Sharpen the image using Kernel Sharpening Technique**


def final_image(rotated):
    # Create our shapening kernel, it must equal to one eventually
    kernel_sharpening = np.array([[0,-1,0], 
                                [-1, 5,-1],
                                [0,-1,0]])
    # applying the sharpening kernel to the input image & displaying it.
    sharpened = cv2.filter2D(rotated, -1, kernel_sharpening)
    sharpened=increase_brightness(sharpened,30)  
    return sharpened


# ## 1. Pass the image through the transformation function to crop out the biggest contour

# ## 2. Brighten & Sharpen the image to get a final cleaned image

path = "/home/hamza/Desktop/"
image = cv2.imread("path of image")    

blurred_threshold = transformation(image)
cleaned_image = final_image(blurred_threshold)
cv2.imwrite(path + "Final_Image4.jpg", cleaned_image)

图片

  1. first pic

  2. second image

编辑 1:

图1test image 1

图2test image 2

图3test image 3

图4test image 4

编辑 2: 如果我只通过黑白图像可以消除剪切,你可以试试如果它有效,请与我分享。

图片:

black and white image

注意:如果图像未剪切,则该特定图像应显示完全相同意味着代码不应触及它。希望你明白了。

【问题讨论】:

    标签: python opencv image-processing computer-vision cv2


    【解决方案1】:

    由于您的初始图像是彩色的,另一种方法是使用 H 位置来检测纸张的“白色”。我对代码进行了一些调整,现在它适用于您的两个图像。

    import numpy as np
    import cv2
    import imutils
    
    def order_points(pts):
        """ Return sorted list of corners, from top-left then clockwise """
        pts = np.reshape(pts, (6,2))
        rect = np.zeros((4, 2), dtype = "float32")
        s = pts.sum(axis = 1)
        rect[0] = pts[np.argmin(s)]
        rect[2] = pts[np.argmax(s)]
        diff = np.diff(pts, axis = 1)
        rect[1] = pts[np.argmin(diff)]
        rect[3] = pts[np.argmax(diff)]
        return rect
    
    def four_point_transform(image, pts):
        (tl, tr, br, bl) = rect
        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.array([
            [0, 0],
            [maxWidth - 1, 0],
            [maxWidth - 1, maxHeight - 1],
            [0, maxHeight - 1]], dtype = "float32")
        M = cv2.getPerspectiveTransform(rect, dst)
        warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
        return warped
    
    image1 = cv2.imread('im1.jpg')
    mask = np.zeros(image1.shape, np.uint8)
    gray = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
    
    # Hue thresholding for the white paper
    HSV = cv2.cvtColor(image1, cv2.COLOR_BGR2HSV)
    lo_H = 100
    hi_H = 200
    thresh = cv2.inRange(HSV, (lo_H, 0, 0), (hi_H, 255, 255))
    
    # Find the contour of the paper sheet - use convexhull
    contours, hierarchy = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    cnt = sorted(contours, key=cv2.contourArea, reverse=True)
    hull = []
    for i in range(len(cnt)):
        hull.append(cv2.convexHull(cnt[i], False))
    
    cv2.drawContours(mask, hull, 0, (255, 255, 255), thickness=cv2.FILLED)
    
    mask = cv2.cvtColor(mask,cv2.COLOR_BGR2GRAY)
    gray = cv2.bitwise_and(gray, gray, mask=mask)
    
    # Corner detection - keep 6 best corners 
    corners = cv2.goodFeaturesToTrack(mask, 6, 0.01, 50)
    corners = np.int0(corners)
    
    # Order the corners and keep 4
    rect = order_points(corners)
    wrap = four_point_transform(gray, rect)
    
    
    # Display results
    cv2.drawContours(image1, hull, 0, (0,255,125), 3)
    cv2.imshow("image", image1)
    #cv2.imshow('thresh', thresh)
    #cv2.imshow("mask", mask)
    cv2.imshow("gray", gray)
    cv2.imshow("wrap", wrap)
    

    【讨论】:

    • 它不适用于所有图像。我尝试了更多图像,但没有正确显示输出。我已经编辑了我的问题并添加了更多图像来测试您的代码。你可以运行它..
    【解决方案2】:

    您的图像没有任何问题,我测试了您的代码,并且确实第一张图像与您编写的代码一起使用,对于第二张图像,通过一些快速调试,您可以发现在您的转换函数中没有找到轮廓- 你有障碍:

    if approx_contour is not None and len(approx_contour)==4:
        approx_contour=np.float32(approx_contour)
        dst=four_point_transform(threshold,approx_contour)
    

    只需添加:

    else:
        print("no contour found")
    

    亲眼看看。

    问题在于您的 Canny 过滤器。使用apertureSize = 7,您的第一张图片有效,但第二张无效,apertureSize = 3 您的第二张图片有效,但第一张无效。

    因此,您的两个图像都有效,但参数不同。如果处理时间对您的任务来说不是问题,您可以迭代多个参数值,或者避开 Canny 方法。在您的两张图像上,纸张都比背景亮很多,因此阈值图像上的凸包可以工作。

    【讨论】:

    • 你能告诉我如何从图像中去除剪切力吗?我正在尝试许多代码但无法正常工作,如果您能告诉我除此方法之外的其他方法,那将不胜感激。我只需要消除它的剪切力。
    猜你喜欢
    • 2019-03-15
    • 2023-03-10
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多