从带有Python的图像中删除特定颜色的所有内容(具有颜色变化的耐受性)

发布于 2025-01-25 12:44:29 字数 720 浏览 5 评论 0原文

我在蓝色#00A2E8中有一些文本,在png图像(白色背景)上用黑色文字。

如何用python pil或openCV在图像上以蓝色(包括蓝色的文本)删除所有内容,并且对颜色的变化具有一定的容忍度?

的确,文本的每个像素都不是完美的相同的颜色,有变化,蓝色阴影。

这是我在想的是:

  • 从RGB转换为HSV
  • 查找蓝色的色调H0
  • 在间隔[H0-10,H0+10]中为色相做一个numpy掩码。 >
  • 在编码此之前,将这些像素设置为白色

,是否有一种更标准的方法可以使用PIL或OPENCV PYTHON来执行此操作?

示例 png file foobar应删除块

“在此处输入图像描述”

I have some text in blue #00a2e8, and some text in black on a PNG image (white background).

How to remove everything in blue (including text in blue) on an image with Python PIL or OpenCV, with a certain tolerance for the variations of color?

Indeed, every pixel of the text is not perfectly of the same color, there are variations, shades of blue.

Here is what I was thinking:

  • convert from RGB to HSV
  • find the Hue h0 for the blue
  • do a Numpy mask for Hue in the interval [h0-10, h0+10]
  • set these pixels to white

Before coding this, is there a more standard way to do this with PIL or OpenCV Python?

Example PNG file: foo and bar blocks should be removed

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

墨小沫ゞ 2025-02-01 12:44:29

您的图像有一些问题。首先,它具有完全多余的α通道,可以忽略。其次,蓝色周围的颜色与蓝色相当长!

我使用了您的计划方法,发现删除非常差:

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image
im = cv2.imread('nwP8M.png')

# Define lower and upper limits of our blue
BlueMin = np.array([90,  200, 200],np.uint8)
BlueMax = np.array([100, 255, 255],np.uint8)

# Go to HSV colourspace and get mask of blue pixels
HSV  = cv2.cvtColor(im,cv2.COLOR_BGR2HSV)
mask = cv2.inRange(HSV, BlueMin, BlueMax)

# Make all pixels in mask white
im[mask>0] = [255,255,255]
cv2.imwrite('DEBUG-plainMask.png', im)

这给出了:

“在此处输入图像说明”

如果您扩大了范围,要获得粗糙的边缘,您就开始影响绿色字母因此,在蓝色附近的空间上,像素 是白色的,像素 在蓝色附近:

# Try dilating (enlarging) mask with 3x3 structuring element
SE   = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask = cv2.dilate(mask, kernel, iterations=1)

# Make all pixels in mask white
im[mask>0] = [255,255,255]
cv2.imwrite('result.png', im)

<

a href =“ https://i.sstatic 。

​具有其他图像的实际值,但原理是相同的。

Your image has some issues. Firstly, it has a completely superfluous alpha channel which can be ignored. Secondly, the colours around your blues are quite a long way from blue!

I used your planned approach and found the removal was pretty poor:

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image
im = cv2.imread('nwP8M.png')

# Define lower and upper limits of our blue
BlueMin = np.array([90,  200, 200],np.uint8)
BlueMax = np.array([100, 255, 255],np.uint8)

# Go to HSV colourspace and get mask of blue pixels
HSV  = cv2.cvtColor(im,cv2.COLOR_BGR2HSV)
mask = cv2.inRange(HSV, BlueMin, BlueMax)

# Make all pixels in mask white
im[mask>0] = [255,255,255]
cv2.imwrite('DEBUG-plainMask.png', im)

That gives this:

enter image description here

If you broaden the range, to get the rough edges, you start to affect the green letters, so instead I dilated the mask so that pixels spatially near the blues are made white as well as pixels chromatically near the blues:

# Try dilating (enlarging) mask with 3x3 structuring element
SE   = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
mask = cv2.dilate(mask, kernel, iterations=1)

# Make all pixels in mask white
im[mask>0] = [255,255,255]
cv2.imwrite('result.png', im)

That gets you this:

enter image description here

You may wish to diddle with the actual values for your other images, but the principle is the same.

荭秂 2025-02-01 12:44:29

我想用另一种方法来鸣叫。我的基本想法是将图像从bgr转换为实验室色彩空间如果我可以将区域隔离为蓝色。这可以通过关注实验室的B组件来完成,因为它代表了从黄色到蓝色的颜色。

代码

img = cv2.imread('image_path', cv2.IMREAD_UNCHANGED)
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
b_component = lab[:,:,2]

注意: 蓝色区域实际上更暗,因此可以很容易地隔离。)

th = cv2.threshold(b_component,127,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]

i.sstatic.net/oxokj.jpg“ rel =“ nofollow noreferrer 应用阈值后,图像在包含数字文本的区域周围包含一些不需要的白色像素,我们不想考虑这些文本。

为了避免有多余的区域,我尝试了以下内容:

  • 在特定区域上方找到轮廓,并在
  • 每个轮廓的矩形边界框架区域上绘制每个区域的每个区域。
  • 在阈值图像上的那个边界框区域中找到255(白色)的像素
  • 将这些像素值更改为原始PNG图像上的白色。

在下面的代码中:

# finding contours
contours = cv2.findContours(th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# initialize a mask of image shape and make copy of original image
black = np.zeros((img.shape[0], img.shape[1]), np.uint8)
res = img.copy()

# draw only contours above certain area on the mask
for c in contours:
    area = cv2.contourArea(c)
    if int(area) > 200:
            cv2.drawContours(black, [c], 0, 255, -1)

如果您看到以下蒙版,它将所有像素的所有像素都包含在轮廓中。但是,“ bar”一词中的像素应不考虑

仅隔离具有蓝色像素的区域,我们执行”和“用阈值图像th

mask = cv2.bitwise_and(th, th, mask = black)

”

我们实际上得到了我们真正想要的掩码。 蒙版中的白色区域在原始图像res的副本中制成白色:

res[mask == 255] = (255, 255, 255, 255)

”

但是上面的图像不是不是完美。 Foo一词的边缘周围仍然可以看到一些区域。

在以下内容中,我们扩张掩码并重复。

res = img.copy()
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
dilate = cv2.dilate(mask, kernel_ellipse, iterations=1) 
res[dilate == 255] = (255, 255, 255, 255)

注意: 使用实验室颜色空间的A和B组件,您可以很容易地隔离不同的颜色,而无需花费时间搜索范围。还可以分割带有阴影和饱和的颜色。

I would like to chime in with a different approach. My basic idea is convert the image from BGR to LAB color space and figure out if I can isolate the regions in blue. This can be done by focusing on the b-component of LAB, since it represents the color from yellow to blue.

Code

img = cv2.imread('image_path', cv2.IMREAD_UNCHANGED)
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
b_component = lab[:,:,2]

(Note: The blue regions are actually quite darker such that it can be isolated easily.)

enter image description here

th = cv2.threshold(b_component,127,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)[1]

But after applying threshold, the image contains some unwanted white pixels around the regions containing numeric text, which we do not want to consider.

enter image description here

To avoid the unwanted regions I tried out the following:

  • Find contours above a certain area and draw each of them on 2-channel mask
  • Mask out rectangular bounding box area for each contour.
  • Locate pixels within that bounding box area that are 255 (white) on the threshold image
  • Change those pixel values to white on the original PNG image.

In code below:

# finding contours
contours = cv2.findContours(th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]

# initialize a mask of image shape and make copy of original image
black = np.zeros((img.shape[0], img.shape[1]), np.uint8)
res = img.copy()

# draw only contours above certain area on the mask
for c in contours:
    area = cv2.contourArea(c)
    if int(area) > 200:
            cv2.drawContours(black, [c], 0, 255, -1)

If you see the following mask, it has enclosed all pixels within the contour in white. However, the pixels within the word "bar" should not be considered.

enter image description here

To isolate only the region with blue pixels, we perform "AND" operation with the threshold image th

mask = cv2.bitwise_and(th, th, mask = black)

enter image description here

We got the mask we actually want. The regions that are white in mask are made white in the copy of the original image res:

res[mask == 255] = (255, 255, 255, 255)

enter image description here

But the above image is not perfect. There are some regions still visible around the edges of the word foo.

In the following we dilate mask and repeat.

res = img.copy()
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
dilate = cv2.dilate(mask, kernel_ellipse, iterations=1) 
res[dilate == 255] = (255, 255, 255, 255)

enter image description here

Note: Using the A and B components of LAB color space you can isolate different colors quite easily, without having to spend time searching for the range. Colors with nearby shading and saturation can also be segmented.

挽清梦 2025-02-01 12:44:29

我认为您正在寻找功能inrange:

thresh = 5
bgr = [255 - thresh, thresh , thresh ]
minBGR = np.array([bgr[0] - thresh, bgr[1] - thresh, bgr[2] - thresh])
maxBGR = np.array([bgr[0] + thresh, bgr[1] + thresh, bgr[2] + thresh])
maskBGR = cv2.inRange(image, minBGR, maxBGR)
resultBGR = cv2.bitwise_or(image, maskBGR)

I think you are looking for the function inRange:

thresh = 5
bgr = [255 - thresh, thresh , thresh ]
minBGR = np.array([bgr[0] - thresh, bgr[1] - thresh, bgr[2] - thresh])
maxBGR = np.array([bgr[0] + thresh, bgr[1] + thresh, bgr[2] + thresh])
maskBGR = cv2.inRange(image, minBGR, maxBGR)
resultBGR = cv2.bitwise_or(image, maskBGR)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文