如何从图像中删除或清除轮廓? [英] How to delete or clear contours from image?

查看:186
本文介绍了如何从图像中删除或清除轮廓?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用车牌,我要做的是在其上应用一系列过滤器,例如:

I'm working with license plates, what I do is apply a series of filters to it, such as:

  1. 灰度
  2. 模糊
  3. 阈值
  4. 二进制

问题是当我这样做时,边框上有一些像这样的图像轮廓,如何清除它们?或仅使其为黑色(蒙版)?我使用了这段代码,但有时会掉下来.

The problem is when I doing this, there are some contour like this image at borders, how can I clear them? or make it just black color (masked)? I used this code but sometimes it falls.

# invert image and detect contours
inverted = cv2.bitwise_not(image_binary_and_dilated)
contours, hierarchy = cv2.findContours(inverted,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

# get the biggest contour
biggest_index = -1
biggest_area = -1
i = 0
for c in contours:
    area = cv2.contourArea(c)
    if area > biggest_area:
        biggest_area = area
        biggest_index = i
    i = i+1

print("biggest area: " + str(biggest_area) + " index: " + str(biggest_index))

cv2.drawContours(image_binary_and_dilated, contours, biggest_index, [0,0,255])
center, size, angle = cv2.minAreaRect(contours[biggest_index])

rot_mat = cv2.getRotationMatrix2D(center, angle, 1.)

#cv2.warpPerspective()
print(size)
dst = cv2.warpAffine(inverted, rot_mat, (int(size[0]), int(size[1])))

mask = dst * 0
x1 = max([int(center[0] - size[0] / 2)+1, 0])
y1 = max([int(center[1] - size[1] / 2)+1, 0])
x2 = int(center[0] + size[0] / 2)-1
y2 = int(center[1] + size[1] / 2)-1

point1 = (x1, y1)
point2 = (x2, y2)
print(point1)
print(point2)

cv2.rectangle(dst, point1, point2, [0,0,0])
cv2.rectangle(mask, point1, point2, [255,255,255], cv2.FILLED)

masked = cv2.bitwise_and(dst, mask)

#cv2_imshow(imgg)
cv2_imshow(dst)
cv2_imshow(masked)
#cv2_imshow(mask)

一些结果:

原始板块是:

  1. 好结果1
  2. 好结果2
  3. 好结果3
  4. 好结果4
  5. 结果1错误
  6. 结果2错误
  1. Good result 1
  2. Good result 2
  3. Good result 3
  4. Good result 4
  5. Bad result 1
  6. Bad result 2

二元板是:

  1. 图片1
  2. 图片2
  3. 图片3
  4. 图片4
  5. 图片5-错误结果1
  6. 图片6-错误结果2
  1. Image 1
  2. Image 2
  3. Image 3
  4. Image 4
  5. Image 5 - Bad result 1
  6. Image 6 - Bad result 2

如何解决此代码?只是我想避免这种不好的结果或改善它.

How can I fix this code? only that I want to avoid that bad result or improve it.

推荐答案

引入

您要问的内容开始变得复杂,并且我相信不再有正确错误的答案,而只是通过不同的方法来实现.几乎所有这些方法都会产生正面和负面的结果,很可能会以不同的比率出现.获得100%的积极结果是一项艰巨的任务,我相信我的答案无法实现.但这可能是为实现该目标而进行更复杂的工作的基础.

What you are asking starts to become complicated, and I believe there is not anymore a right or wrong answer, just different ways to do this. Almost all of them will yield positive and negative results, most likely in a different ratio. Having a 100% positive result is quite a challenging task, and I do believe my answer does not reach it. Yet it can be the basis for a more sophisticated work towards that goal.

我的建议

所以,我想在这里提出一个不同的建议. 我不确定100%为什么要执行所有步骤,并且我相信其中某些步骤可能是不必要的. 让我们从问题开始:您要删除边框上的白色部分(不是数字). 因此,我们需要一个关于如何将它们与字母区分开的想法,以便正确解决它们. 如果我们只是尝试绘制轮廓和变形,它可能会在某些图像上起作用,而在其他图像上却不会起作用,因为并非所有图像看起来都一样.这是拥有适用于许多图像的通用解决方案的最困难的问题.

So, I want to make a different proposal here. I am not 100% sure why you are doing all the steps, and I believe some of them could be unnecessary. Let's start from the problem: you want to remove the white parts on the borders (which are not numbers). So, we need an idea about how to distinguish them from the letters, in order to correctly tackle them. If we just try to contour and warp, it is likely to work on some images and not on others, because not all of them look the same. This is the hardest problem to have a general solution that works for many images.

数字的特征与边界(和其他小点)的特征之间有什么区别: 考虑一下之后,我会说:形状!就是说,如果您想像一个字母/数字周围的边界框,它将看起来像一个矩形,其大小与图像大小有关.在边界情况下,它们通常很大或很窄,或者太小而不能视为字母/数字(随机点).

What are the difference between the characteristics of the numbers and the characteristics of the borders (and other small points?): after thinking about that, I would say: the shapes! That meaning, if you would imagine a bounding box around a letter/number, it would look like a rectangle, whose size is related to the image size. While in the case of the border, they are usually very large and narrow, or too small to be considered a letter/number (random points).

因此,我的猜测是在分割上,通过特征的形状划分特征.因此,我们获取二进制图像,我们使用其轴上的投影删除了某些部分(如您在

Therefore, my guess would be on segmentation, dividing the features via their shape. So we take the binary image, we remove some parts using the projection on their axes (as you correctly asked in the previous question and I believe we should use) and we get an image where each letter is separated from the white borders. Then we can segment and check the shape of each segmented object, and if we think these are letters, we keep them, otherwise we discard them.

代码

我之前以您的数据为例编写了代码.在这组图像上调整了一些参数,因此对于较大的数据集,可能必须放宽这些参数.

I wrote the code before as an example on your data. Some of the parameters are tuned on this set of images, so they may have to be relaxed for a larger dataset.

import cv2
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
import scipy.ndimage as ndimage

# do this for all the images
num_images = 6
plt.figure(figsize=(16,16))
for k in range(num_images):

    # read the image
    binary_image = cv2.imread("binary_image/img{}.png".format(k), cv2.IMREAD_GRAYSCALE)
    # just for visualization purposes, I create another image with the same shape, to show what I am doing
    new_intermediate_image = np.zeros((binary_image.shape), np.uint8)
    new_intermediate_image += binary_image
    # here we will copy only the cleaned parts
    new_cleaned_image = np.zeros((binary_image.shape), np.uint8)

    ### THIS CODE COMES FROM THE PREVIOUS ANSWER: 
    # https://stackoverflow.com/questions/62127537/how-to-clean-binary-image-using-horizontal-projection?noredirect=1&lq=1
    (rows,cols)=binary_image.shape
    h_projection = np.array([ x/rows for x in binary_image.sum(axis=0)])
    threshold_h = (np.max(h_projection) - np.min(h_projection)) / 10
    print("we will use threshold {} for horizontal".format(threshold))
    # select the black areas
    black_areas_horizontal = np.where(h_projection < threshold_h)
    for j in black_areas_horizontal:
        new_intermediate_image[:, j] = 0

    v_projection = np.array([ x/cols for x in binary_image.sum(axis=1)])
    threshold_v = (np.max(v_projection) - np.min(v_projection)) / 10
    print("we will use threshold {} for vertical".format(threshold_v))
    black_areas_vertical = np.where(v_projection < threshold_v)
    for j in black_areas_vertical:
        new_intermediate_image[j, :] = 0
    ### UNTIL HERE

    # define the features we are looking for
    # this parameters can also be tuned
    min_width = binary_image.shape[1] / 14
    max_width = binary_image.shape[1] / 2
    min_height = binary_image.shape[0] / 5
    max_height = binary_image.shape[0]
    print("we look for feature with width in [{},{}] and height in [{},{}]".format(min_width, max_width, min_height, max_height))
    # segment the iamge
    labeled_array, num_features = ndimage.label(new_intermediate_image)

    # loop over all features found
    for i in range(num_features):
        # get a bounding box around them
        slice_x, slice_y = ndimage.find_objects(labeled_array==i)[0]
        roi = labeled_array[slice_x, slice_y]
        # check the shape, if the bounding box is what we expect, copy it to the new image
        if roi.shape[0] > min_height and \
            roi.shape[0] < max_height and \
            roi.shape[1] > min_width and \
            roi.shape[1] < max_width:
            new_cleaned_image += (labeled_array == i)

    # print all images on a grid
    plt.subplot(num_images,3,1+(k*3))
    plt.imshow(binary_image)
    plt.subplot(num_images,3,2+(k*3))
    plt.imshow(new_intermediate_image)
    plt.subplot(num_images,3,3+(k*3))
    plt.imshow(new_cleaned_image)

产生输出的

(在网格中,左侧图像是输入图像,中央图像是基于直方图投影的蒙版之后的图像,右侧是清洁的图像):

that produces the output (in the grid, left image are the input images, central one are the images after the mask based on histogram projections, and on the right are the cleaned images):

结论:

如上所述,该方法未产生100%的阳性结果.最后一张图片的质量较低,并且某些部分未连接,并且在此过程中丢失了它们.我个人认为这是获得更清晰图像的代价,如果您有很多图像,这将不是问题,可以删除这些图像.总的来说,我认为此方法返回的图像非常清晰,其中所有非字母或数字的其他部分均已正确删除.

As said above, this method does not yield 100% positive results. The last picture has lower quality and some parts are unconnected, and they are lost in the process. I personally believe this is a price to pay to get cleaner image, and if you have a lot of images, it won't be a problem, and you can remove those kind of images. Overall, I think this method returns quite clear images, where all other parts that are not letters or numbers are correctly removed.

优势

  • 图像干净,仅保留字母或数字

  • the image is clean, nothing more than letters or numbers are kept

参数可以调整,并且在图像之间应该保持一致

the parameters can be tuned, and should be consistent across images

在出现问题的情况下,在选择保留功能的循环上进行一些打印或调试可以更容易地了解问题所在并进行纠正

in case of problem, using some prints or some debugging on the loop that chooses the features to keep should make it easier to understand where are the problem and correct them

限制

  • 在某些字母和数字触摸白色边框的情况下可能会失败,这似乎很有可能.它是通过使用投影创建的black_areas处理的,但我不太确定这会在100%的时间内起作用.

  • it may fail in some cases where letters and numbers touch the white borders, which seems quite possible. It is handled from the black_areas created using the projection, but I am not so confident this will work 100% of the time.

一些数字的小部分可能会在此过程中丢失,如上图所示.

some small parts of the numbers can be lost during the process, as in the last picture.

这篇关于如何从图像中删除或清除轮廓?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆