【问题标题】:Overwrite the pixels closest to blue with (0,0,255) blue用 (0,0,255) 蓝色覆盖最接近蓝色的像素
【发布时间】:2020-07-28 17:09:30
【问题描述】:

我正在使用 Python 和 PIL(或 Pillow)并希望在包含给定强度的两个像素和 RGB 代码 (0,0,255) 的文件上运行代码。

像素也可能接近 (0,0,255) 但略有调整,即 (0,1,255)。我想用 (0,0,255) 覆盖最接近 (0,0,255) 的两个像素。

这可能吗?如果有,怎么做?

这是一个示例图像,这里用我想要“更蓝”的像素进行了缩放

我正在查看的代码尝试来自这里:

# import the necessary packages
import numpy as np
import scipy.spatial as sp
import matplotlib.pyplot as plt
import cv2
from PIL import Image, ImageDraw, ImageFont

#Stored all RGB values of main colors in a array
# main_colors = [(0,0,0),
#                   (255,255,255),
#                   (255,0,0),
#                   (0,255,0),
#                   (0,0,255),
#                   (255,255,0),
#                   (0,255,255),
#                   (255,0,255),
#                   ] 

main_colors = [(0,0,0),
                  (0,0,255),
                  (255,255,255)
                  ] 


background = Image.open("test-small.tiff").convert('RGBA')
background.save("test-small.png")

retina = cv2.imread("test-small.png")
#convert BGR to RGB image
retina = cv2.cvtColor(retina, cv2.COLOR_BGR2RGB)

h,w,bpp = np.shape(retina)

#Change colors of each pixel
#reference :https://stackoverflow.com/a/48884514/9799700
for py in range(0,h):
    for px in range(0,w):
      ########################
      #Used this part to find nearest color 
      #reference : https://stackoverflow.com/a/22478139/9799700
      input_color = (retina[py][px][0],retina[py][px][1],retina[py][px][2])
      tree = sp.KDTree(main_colors) 
      ditsance, result = tree.query(input_color) 
      nearest_color = main_colors[result]
      ###################
      
      retina[py][px][0]=nearest_color[0]
      retina[py][px][1]=nearest_color[1]
      retina[py][px][2]=nearest_color[2]
      print(str(px), str(py))
    
# show image
plt.figure()
plt.axis("off")
plt.imshow(retina)
plt.savefig('color_adjusted.png')

我的逻辑是将最接近的 RGB 颜色数组替换为仅包含 (0,0,255)(我想要的蓝色)和白色可能包含 (255,255,255) - 这样只有黑色、白色或蓝色的像素才能通过.

我已在较小的图像上运行代码,它会根据需要将此 转换为

但是,代码会遍历每个像素,这对于较大的图像来说很慢(我使用的是 4000 x 4000 像素的图像)。我还想将图像输出并保存到与原始文件相同的尺寸(我希望在使用 plt.savefig 时可以选择。

如果这可以优化,那将是理想的。同样,选择两个“最蓝”(即最接近 (0,0,255))像素并用 (0,0,255) 重写它们对我来说应该更快且同样有效。

【问题讨论】:

  • 您的链接似乎无效。此外,当您实际使用 OpenCV 时,您已经标记并说您正在使用 PIL。
  • 修复了链接,并在我使用库打开 .tiff 并将其转换为该脚本的 .png 时保留了 PIL 标记(也更改了脚本)。
  • 您的问题现在似乎不同了!最初,您想让最接近蓝色的两个像素变为完全蓝色,而其他颜色像素保持不变。这将给出具有 257 种颜色的输出图像,即蓝色和 256 种灰度。现在您似乎希望每个像素都呈现黑色、白色或蓝色,从而产生只有 3 种颜色的输出图像?
  • 嗨,马克!老实说,前者更可取,只是我似乎对后者有解决方案。两者都符合我的目的,但出于速度目的,我肯定更喜欢前者。我认为后者会产生更精确的结果(因为只有三种颜色),但在处理所有 4000^2 像素时会慢得多。
  • 嗨@MarkSetchell!对于那个很抱歉。刚刚点击它。

标签: python opencv matplotlib python-imaging-library


【解决方案1】:

由于您的图像大部分是不饱和灰色,只有几个蓝色像素,因此转换为 HLS 色彩空间并寻找饱和像素会更快。如果您想将其缩小到两个,您可以轻松地对已识别的像素进行进一步测试:

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image
im  = cv2.imread('eye.png', cv2.IMREAD_COLOR)

# Convert to HLS, so we can find saturated blue pixels
HLS = cv2.cvtColor(im,cv2.COLOR_BGR2HLS)

# Get x,y coordinates of pixels that have high saturation
SatPix = np.where(HLS[:,:,2]>60)
print(SatPix)

# Make them pure blue and save result
im[SatPix] = [255,0,0]
cv2.imwrite('result.png',im)

输出

(array([157, 158, 158, 272, 272, 273, 273, 273]), array([55, 55, 56, 64, 65, 64, 65, 66]))

这意味着像素 157,55 和 158,55,以及 158,56 等都是蓝色的。在我的 Mac 上,转换为 HLS 色彩空间、识别饱和像素并将它们设置为纯蓝色需要 758 微秒。


你可以在命令行上使用 ImageMagick 来实现相同类型的事情,而无需编写任何 Python:

magick eye.png -colorspace hsl -channel g -separate -auto-level result.png

【讨论】:

  • 谢谢!我想运行我剩余的代码(一个循环来搜索最接近 (0,0,255) 的 RGB 值,使用来自 SatPix 的数组。我如何将它合并到这个循环中?(stackoverflow.com/questions/63143843/…)我正在尝试打印数组,但我在每个数组中只得到一个值。
  • SatPix 是一个包含 2 个数组的元组。 SatPix[0] 包含所有饱和像素的 y 坐标,SatPix[1] 包含所有 x 坐标。所以第一个蓝色像素有坐标SatPix[0][0]SatPix[1][0]。第二个蓝色像素有坐标SatPix[0][1]SatPix[1][1] 等等。找到的像素数为len(SatPix[0])
  • 好的。你能解释一下“np.where(HLS[:,:,2]>60)”吗?是否选择饱和度 (S) 值 > 60 的像素?
  • 是的,完全正确。 HLS[:,:,0] 存储每个像素的色调,HLS[:,:,1] 存储每个像素的亮度,HLS[:,:,2] 存储饱和度。
  • 谢谢!我为 RGB (B > 0) 添加了一个阈值。这与 HLS 建议相结合,使得处理速度非常快。太感谢了!这是代码:RGBPix = np.where(np.logical_and((RGB[:,:,2]>0),(HLS[:,:,2]>40)))
【解决方案2】:

这是一种不同的方法。使用 SciPycdist() 计算每个像素到蓝色的欧几里得距离,然后选择最近的两个:

#!/usr/bin/env python3

import cv2
import numpy as np
from scipy.spatial.distance import cdist

# Load image, save shape, reshape as tall column of 3 RGB values
im  = cv2.imread('eye.png', cv2.IMREAD_COLOR)
origShape = im.shape
im  = im.reshape(-1,3)

# Work out distance to pure Blue for each pixel
blue = np.full((1,3), [255, 0 , 0])
d    = cdist(im, blue, metric='euclidean')   # THIS LINE DOES ALL THE WORK

indexNearest     = np.argmin(d) # get index of pixel nearest to blue
im[np.argmin(d)] = [0,0,255]    # make it red
d[indexNearest]  = 99999        # make it appear further so we don't find it again

indexNearest     = np.argmin(d) # get index of pixel second nearest to blue
im[np.argmin(d)] = [0,0,255]    # make it red

# Reshape back to original shape and save result
im = im.reshape(origShape)
cv2.imwrite('result.png',im)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 2019-02-07
    • 2021-05-14
    相关资源
    最近更新 更多