【问题标题】:Python: How to implement Binary Filter on RGB image? (algorithm)Python:如何在 RGB 图像上实现二进制过滤器? (算法)
【发布时间】:2018-12-16 23:39:39
【问题描述】:

我正在尝试使用 python 和 PyQT5 实现二进制图像过滤器(以获取单色二进制图像),并且为了检索新的像素颜色,我使用以下方法:

def _new_pixel_colors(self, x, y):
    color = QColor(self.pixmap.pixel(x, y))

    result = qRgb(0, 0, 0) if all(c < 127 for c in color.getRgb()[:3]) else qRgb(255, 255, 255)

    return result

这可能是 RGB 图像的二元滤镜的正确样本吗?我的意思是,这是检查像素是比(127,127,127)灰色更亮或更暗的充分条件吗? 请不要使用 opencv、pillow 等提供任何解决方案。我只是询问算法本身。

【问题讨论】:

  • 已经回答/接受,但我想添加抖动,因为人们忘记了它,结果明显更好......所以我用这种方法和例子添加了答案

标签: python image algorithm filter graphics


【解决方案1】:

我至少会比较强度i=R+G+B ...

对于 ROI 之类的蒙版,您可以使用任何阈值技术(自适应阈值是最好的),但如果您生成的图像不是 ROI掩码并且应该类似于原始图像的视觉特征,那么我所知道的最佳转换是使用Dithering

BW 抖动背后的想法是将灰度转换为 BW 模式,从而保留阴影。结果通常很嘈杂,但保留了更多的视觉细节。这里简单的 C++ 抖动(抱歉不是 Python 编码器):

picture pic0,pic1;
    // pic0 - source img
    // pic1 - output img
int x,y,i;
color c;
// resize output to source image size clear with black
pic1=pic0; pic1.clear(0);
// dithering
i=0;
for (y=0;y<pic0.ys;y++)
 for (x=0;x<pic0.xs;x++)
    {
    // get source pixel color (AARRGGBB)
    c=pic0.p[y][x];
    // add to leftovers
    i+=WORD(c.db[picture::_r]); // _r,_g,_b are just constants 0,1,2
    i+=WORD(c.db[picture::_g]);
    i+=WORD(c.db[picture::_b]);
    // threshold white intensity is 255+255+255=765
    if (i>=384){ i-=765; c.dd=0x00FFFFFF; } else c.dd=0;
    // copy to destination image
    pic1.p[y][x]=c;
    }

所以它与上面的链接相同,但只使用黑白。 i 是要放置在图像上的累积强度。 xs,ys 是分辨率,c.db[] 是颜色通道访问。

如果我将它应用到这样的彩色图像上:

结果如下:

正如您所看到的,所有细节都保留了下来,但出现了嘈杂的图案……出于打印目的,有时图像的分辨率会成倍增加以提高质量。如果您使用更好的模式(如 16x16 正方形等)更改 naive 2 嵌套 for 循环,则噪声将在其源限制伪影附近保留。还有一些使用伪随机模式的方法(将剩余的i 放在其源像素附近的随机位置)甚至更好......

但是对于 BW 抖动,即使是简单的方法也足够了,因为伪像只有一个像素大小。对于彩色抖动,伪影可能会创建几个像素大小的不需要的水平线图案(取决于使用的调色板不匹配,越差的调色板越大……)

PS 只是为了与其他答案阈值输出进行比较,这是相同的抖动图像:

【讨论】:

    【解决方案2】:

    Image thresholding 是您正在寻找的算法类别 - 二进制阈值会将像素设置为 0 或 1,是的。

    根据所需的输出,考虑首先将您的图像转换为具有亮度通道的其他色彩空间,尤其是 HSL。使用(127, 127, 127)作为阈值并没有统一考虑亮度,因为RGB的每个通道都是R、G或B的饱和度;考虑这张图片:

    from PIL import Image
    import colorsys
    
    
    def threshold_pixel(r, g, b):
        h, l, s = colorsys.rgb_to_hls(r / 255., g / 255., b / 255.)
        return 1 if l > .36 else 0
        # return 1 if r > 127 and g > 127 and b > 127 else 0
    
    
    def hlsify(img):
        pixels = img.load()
        width, height = img.size
    
        # Create a new blank monochrome image.
        output_img = Image.new('1', (width, height), 0)
        output_pixels = output_img.load()
    
        for i in range(width):
            for j in range(height):
                output_pixels[i, j] = threshold_pixel(*pixels[i, j])
    
        return output_img
    
    
    binarified_img = hlsify(Image.open('./sample_img.jpg'))
    binarified_img.show()
    binarified_img.save('./out.jpg')
    

    其他 StackExchange 网站上有很多关于此主题的讨论,例如

    Binarize image data

    How do you binarize a colored image?

    how can I get good binary image using Otsu method for this image?

    【讨论】:

    • 不错的答案,所以+1 ...我添加了我自己的抖动方法,以防你感兴趣。我还用你的图片作为比较的输入,所以如果你对它有问题,请评论我,我把它记下来(或自己编辑)
    猜你喜欢
    • 2014-12-20
    • 2013-01-17
    • 1970-01-01
    • 2011-10-30
    • 2012-04-26
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 2020-09-02
    相关资源
    最近更新 更多