gpt4 book ai didi

python - 如何从图像中删除或清除轮廓?

转载 作者:行者123 更新时间:2023-12-02 16:09:24 26 4
gpt4 key购买 nike

我正在处理车牌,我所做的是对其应用一系列过滤器,例如:

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

问题是当我这样做时,边界处有一些像这张图片的轮廓,我该如何清除它们?或者让它只是黑色(蒙面)?我用过这段代码,但有时它会掉下来。

# 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)

一些结果:

enter image description here

enter image description here

enter image description here

原始盘子是:

  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. Image 1
  2. Image 2
  3. Image 3
  4. Image 4
  5. Image 5 - Bad result 1
  6. Image 6 - Bad result 2

如何修复此代码?只是我想避免那个糟糕的结果或改善它。

最佳答案

简介

您的问题开始变得复杂,我相信不再有正确错误答案,只是不同的方法。几乎所有这些都会产生正面和负面的结果,很可能是不同的比例。获得 100% 的积极结果是一项非常具有挑战性的任务,我相信我的答案没有达到目的。然而,它可以成为实现该目标的更复杂工作的基础。

我的建议

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

数字的特征和边框的特征(以及其他小点?)有什么区别?想了想,我会说:形状!这意味着,如果您想象一个字母/数字周围的边界框,它看起来就像一个矩形,其大小与图像大小相关。而在边界的情况下,它们通常又大又窄,或者太小而不能被视为字母/数字(随机点)。

因此,我的猜测是分割,通过形状划分特征。所以我们获取二进制图像,我们使用轴上的投影删除一些部分(正如您在 previous question 中正确询问的那样,我相信我们应该使用),我们得到一个图像,其中每个字母都与白色边框分开。然后我们可以分割并检查每个分割对象的形状,如果我们认为这些是字母,我们保留它们,否则我们丢弃它们。

代码

我之前写过代码作为你数据的例子。一些参数是针对这组图像进行调整的,因此对于更大的数据集可能需要放宽。

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)

产生输出(在网格中,左边的图像是输入图像,中间的图像是基于直方图投影的掩码后的图像,右边是清理后的图像):

enter image description here enter image description here

结论:

如上所述,此方法不会产生 100% 的阳性结果。最后一张图画质比较差,有些部分没有连起来,在处理过程中丢失了。我个人认为这是为了获得更清晰的图像而付出的代价,如果你有很多图像,那不会有问题,你可以删除那些图像。总的来说,我认为这种方法返回的图像非常清晰,所有其他非字母或数字的部分都被正确移除。

优势

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

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

  • 如果出现问题,在选择要保留的特征的循环中使用一些打印或一些调试应该可以更容易地理解问题出在哪里并纠正它们

限制

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

  • 在这个过程中可能会丢失一些小部分数字,如上图所示。

关于python - 如何从图像中删除或清除轮廓?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62190121/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com