简体   繁体   English

你如何比较像素?

[英]How do you compare pixels?

I am using the PIL to take an image with a black background and make a mask out of it. 我正在使用PIL拍摄黑色背景的图像并从中制作一个遮罩。 What I want the program to do is iterate through all the pixels in the image and if the pixel is black make it white and if it is any other color make it black, but I am not sure how to appropriately compare pixel values to determine what to do with the pixel. 我希望程序做的是迭代图像中的所有像素,如果像素是黑色使其变为白色,如果是任何其他颜色使其变黑,但我不确定如何正确比较像素值以确定什么与像素有关。

Here is my code so far which creates an all black image. 这是我到目前为止的代码,它创建了一个全黑的图像。

import os, sys
import Image

filename = "C:\Users\pdiffley\Dropbox\C++2\Code\Test\BallSpriteImage.bmp"
height   = 50
width    = 50


im = Image.open(filename)
im = im.load()

i = 0
j = 0
while i<height:
    while j<width:
        if im[j,i] == (0,0,0):
            im[j,i] = (255,255,255)
        else:
            im[j,i] = (0,0,0) 
        j = j+1
    i = i+1
mask = Image.new('RGB', (width, height))
newfile = filename.partition('.')
newfile = newfile[0] + "Mask.bmp"

mask.save(newfile)

I believe the problem is in the if statement comparing the im[j,i] to the RGB value (0,0,0) which always evaluates to false. 我认为问题出在if语句中,将im [j,i]与RGB值(0,0,0)进行比较,RGB值总是计算为false。 What is the correct way to compare the pixel? 比较像素的正确方法是什么?

The pixel data comparison is correct. 像素数据比较是正确的。 But there are two problems with the logic: 但逻辑有两个问题:

  1. When you are finished with a row, you should reset j to 0. 完成一行后,应将j重置为0。
  2. You are modifying the object "im", but writing "mask". 您正在修改对象“im”,但是要编写“mask”。

This should work (as long as you have no alpha channel - as andrewdski pointed out): 这应该有用(只要你没有alpha通道 - 正如andrewdski指出的那样):

img = Image.open(filename)
im = img.load()

i = 0
while i<height:
    j = 0
    while j<width:
        if im[j,i] == (0,0,0):
            im[j,i] = (255,255,255)
        else:
            im[j,i] = (0,0,0) 
        j = j+1
    i = i+1
newfile = filename.partition('.')
newfile = newfile[0] + "Mask.png"

img.save(newfile)

The following function uses the .point method and works on separately on each band of the image: 以下函数使用.point方法并在图像的每个波段上单独处理:

CVT_TABLE= (255,) + 255 * (0,)

def do_convert(img):
    return img.point(CVT_TABLE * len(img.getbands()))

Working separately on each band means that a picture like this: 在每个乐队上单独工作意味着这样的图片: 新的太空堡垒卡拉狄加海报
will be converted into this: 将被转换为:
多彩的结果

However, you can get almost what you want if you convert the image to mode "L" first: 但是,如果首先将图像转换为模式“L”,则几乎可以获得所需的内容:

CVT_TABLE= (255,) + 255 * (0,)

def do_convert(img):
    return img.convert("L").point(CVT_TABLE)

producing the following result: 产生以下结果:
几乎但并不完全

The only drawback is that a few darkest colors (eg #000001 , the darkest blue possible) will probably be converted to black by the mode conversion. 唯一的缺点是一些最暗的颜色(例如#000001 ,可能是最暗的蓝色)可能会通过模式转换转换为黑色。

Here's how I'd rewrite it, which avoids a pixel index reset problem by using for loops, writes the data to a separate mask image rather than back onto the source, and removes the hardcoded image size. 这是我如何重写它,它通过使用for循环避免像素索引重置问题,将数据写入单独的掩码图像而不是返回到源,并删除硬编码的图像大小。 I also added an r prefix to the filename string to handle the backslashes in it. 我还在文件名字符串中添加了一个r前缀来处理其中的反斜杠。

import os, sys
import Image

BLACK = (0,0,0)
WHITE = (255, 255, 255)

filename = r"C:\Users\pdiffley\Dropbox\C++2\Code\Test\BallSpriteImage.bmp"

img = Image.open(filename)
width, height = img.size
im = img.load()

mask = Image.new('RGB', (width, height))
msk = mask.load()

for y in xrange(height):
    for x in xrange(width):
        if im[x,y] == BLACK:
            msk[x,y] = WHITE
        else:  # not really needed since mask's initial color is black
            msk[x,y] = BLACK

newfilename = filename.partition('.')
newfilename = newfilename[0] + "Mask.bmp"
mask.save(newfilename)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM