ImageMath.eval提供的结果与手动计算不同

时间:2017-12-15 21:57:03

标签: python python-2.7 python-imaging-library pillow

编辑:在等待查看使用Image.point()时可以考虑哪些可能的解决方案时,我想补充一点,我现在明白为什么我的表达式在ImageMath.eval中不起作用。

ImageMath.eval对整个图像执行单独的操作,而不是逐个像素地执行整个eval语句。所以当我问(a-b)>我真正问的是,如果(a-b)产生的图像是> 255.这是一个荒谬的问题。并且Pillow自动剪辑值,没有选项允许包装在源中。如果我对C ++和编译python库有了更好的理解,我很乐意分叉并改变xD。

但是在获得这些知识之前,我只需要在图书馆之外手动完成。

原始问题: 我有这个减法例程来相互减去图像中的两个通道。 (我使用中间人图像,因为如果我过早加入偏见,偶尔会得到奇怪的结果)

def subChannels(c1,c2,divisor=1,bias=0):
    ecpression = "(a/%s)-(b/%s)" % (divisor,divisor)
    middleman = ImageMath.eval(expression, a=c1, b=c2).convert("L")
    return Image.Math.eval("a + b", a = middleman, b = bias).convert("L")

非常简单。它有效。除非我有偏置/偏移量将值推到255或低于0.然后它只是剪切结果。

现在我尝试添加一个荒谬的if else评估语句,试图为我做包装。

def subChannels(c1,c2,divisor=1,bias=0):
    overflow = "((%s) - 256) if (%s) > 255 else (256 + (%s)) if (%s) < 0 else (%s)"
    sub = "(a/%s)-(b/%s)" % (divisor,divisor)
    expression = overflow % (sub, sub, sub, sub, sub)
    middleman = ImageMath.eval(expression, a=c1, b=c2).convert("L")
    add = "a + b"
    expression = overlfow % (add, add, add, add, add)
    return ImageMath.eval(expression, a=middleman, b = bias).convert("L")

那失败了。生成的图像只能得到一些正确的像素。其余的都被吹灭了,纯白色。真的很奇怪。

然后我尝试手动执行方程式,因为我知道在Python中的图像中循环每个像素会比较慢。

def subChannels(c1,c2,divisor=1, bias=0, clip=True):
    #images have already been resized to match before sending here
    pixels1 = c1.load()
    pixels2 = c2.load()
    for x in range(c1.size[0]):
        for y in range(c1.size[1]):
            r = pixels1[x,y]
            g = pixels2[x,y]
            value = wrapOrClip((r/divisor)-(g/divisor), clip)
            value = wrapOrClip((value + bias), clip)
            pixels2[x,y] = value
    return c2

def wrapOrClip(value, clip = True):
    if clip:
        return max(min(value,255),0)
    else:
        return ((value)) - 256 if ((value)) > 255 else ((value)) + 256 if ((value)) < 0 else ((value))

奇怪的是,结果正是我的预期。所以,出于某种原因,我不明白我的方程式逐像素工作。但是如果用作ImageMath.eval中的表达式,它会产生截然不同的结果。

我更愿意使用eval,因为时间测试eval需要1秒才能完成工作。我的手动方法耗时9秒。

我知道推理中明显的缺陷是什么?

编辑: 包括我正在使用的代码的完整工作版本。

from PIL import ImageGrab, Image, ImageMath, ImageTk
from io import StringIO
import sys

#One stop shop for resizing, splitting, and combining the channels
#for all methods on the dialog

def evalImages(image1,image2, channel1 = -1, channel2 = -1, divisor=1, bias=0, clip=True, mode="add"):
    modes = {"add": addChannels, 
             "sub": subChannels, 
             "mul": mulChannels,
             "and": andChannels,
             "or": orChannels,
             "xor": xorChannels,
             "average": averageChannels,
             "dark": darkChannels,
             "light": lightChannels,
             "diff": diffChannels}
    #resize image 2 to fit image 1         
    if image1.size != image2.size:
        image2 = image2.resize(image1.size, Image.BICUBIC)
    if channel1 == -1:
        #if we are combining all channels
        r1,g1,b1 = image1.split()
        r2,g2,b2 = image2.split()
        r3 = modes[mode](r1,r2,d = divisor, b = bias, clip=clip)
        g3 = modes[mode](g1,g2,d = divisor, b = bias, clip=clip)
        b3 = modes[mode](b1,b2,d = divisor, b = bias, clip=clip)
        return Image.merge("RGB", (r3,g3,b3))
    else:
        #0 = Red, 1 = Green, Blue = 2
        c1 = image1.split()[channel1]
        c2 = image2.split()[channel2]
        return modes[mode](c1, c2, d = divisor, b = bias, clip=clip)

#Function to either wrap the value aroun or clip it at 0/255
def wrapOrClip(value, clip = True):
    if clip:
        return max(min(value,255),0)
    else:
        return ((value)) - 256 if ((value)) > 255 else ((value)) + 256 if ((value)) < 0 else ((value))

#Function subtracts two single band images from each other
#divisor divides the values before they are subtracted
#bias is an offset applie to each pixel after subtraction and clipping or wrapping        
def subChannels(c1,c2,d=1, b=0, clip=True):
    #images have already been resized to match before sending here
    pixels1 = c1.load()
    pixels2 = c2.load()
    for x in range(c1.size[0]):
        for y in range(c1.size[1]):
            r = pixels1[x,y]
            g = pixels2[x,y]
            value = wrapOrClip((r/d)-(g/d), clip)
            value = wrapOrClip((value + b), clip)
            pixels2[x,y] = value
    return c2

#Multiply channels    
def mulChannels(c1,c2,d=1, b=0, clip=True):
    pass

    #Bitwise AND channels
def andChannels(c1,c2, d=1, b=0, clip=True):
    pass

    #Bitwise OR channels
def orChannels(c1,c2, d=1, b=0, clip=True):
    pass

    #Bitwise XOR channels
def xorChannels(c1,c2, d=1, b=0, clip=True):
    pass

#Average the two pixels in each channel together
def averageChannels(c1,c2, d=1, b=0, clip=True):
    pass

# Choose the darkest pixels from both images (min(c1,c2))
def darkChannels(c1,c2, d=1, b=0, clip=True):
    pass

# Choose the lightest pixels from both channels (max(c1, c2))
def lightChannels(c1,c2, d=1, b=0, clip=True):
    pass

# Absolute value after Subtract
def diffChannels(c1,c2, d=1, b=0, clip=True):
    pass

#add both channels together to get a ligher image
def addChannels(c1, c2, d=1, b=0, clip=True):
    #bias is added to end result
    #divisor is applied to each channel individually
    pass

if __name__ == '__main__':
    #I normally have code here to put two images on the clipboad
    #then grab the down with ImageGrab.grapclipboard
    #But that's specific to the program that runs this code.
    #so instead here are two simple open functions
    if len(sys.argv) >= 3:
        print "args are good"
        image1 = Image.open(sys.argv[1])
        image2 = Image.open(sys.argv[2])
        print "files opened"
        #In this example, I'm combining the Red an Green channels of the two images together
        image3 = evalImages(image1, image2,channel1 = 0, channel2=1, divisor = 1, bias=0, mode="sub")
        print "channels merged"
        image3.save("3.jpg")
        print "file saved"

0 个答案:

没有答案