执行与ImageMagick'相同的操作;s"-级别“;在python/PIL中?

执行与ImageMagick'相同的操作;s"-级别“;在python/PIL中?,python,image,image-processing,imagemagick,python-imaging-library,Python,Image,Image Processing,Imagemagick,Python Imaging Library,我想在python中调整图像的颜色级别。我可以使用任何可以轻松安装在Ubuntu桌面上的python库。我想做与ImageMagick的-级别()相同的事情。PIL(Python图像库)似乎没有它。我一直在调用图像上的convert,然后再次读取文件,但这似乎是浪费。有更好/更快的方法吗?为什么不使用?这是Image Magick的Python接口。如果我正确理解了ImageMagick的-level选项,那么我提供的level\u Image函数应该可以满足您的需要 有两点需要注意: 速度肯

我想在python中调整图像的颜色级别。我可以使用任何可以轻松安装在Ubuntu桌面上的python库。我想做与ImageMagick的
-级别
()相同的事情。PIL(Python图像库)似乎没有它。我一直在调用图像上的
convert
,然后再次读取文件,但这似乎是浪费。有更好/更快的方法吗?

为什么不使用?这是Image Magick的Python接口。

如果我正确理解了ImageMagick的
-level
选项,那么我提供的
level\u Image
函数应该可以满足您的需要

有两点需要注意:

  • 速度肯定可以提高
  • 它目前仅适用于RGB图像
  • 该算法通过HSV颜色空间,只影响V(亮度)分量
守则:

import colorsys

class Level(object):

    def __init__(self, minv, maxv, gamma):
        self.minv= minv/255.0
        self.maxv= maxv/255.0
        self._interval= self.maxv - self.minv
        self._invgamma= 1.0/gamma

    def new_level(self, value):
        if value <= self.minv: return 0.0
        if value >= self.maxv: return 1.0
        return ((value - self.minv)/self._interval)**self._invgamma

    def convert_and_level(self, band_values):
        h, s, v= colorsys.rgb_to_hsv(*(i/255.0 for i in band_values))
        new_v= self.new_level(v)
        return tuple(int(255*i)
                for i
                in colorsys.hsv_to_rgb(h, s, new_v))

def level_image(image, minv=0, maxv=255, gamma=1.0):
    """Level the brightness of image (a PIL.Image instance)
    All values ≤ minv will become 0
    All values ≥ maxv will become 255
    gamma controls the curve for all values between minv and maxv"""

    if image.mode != "RGB":
        raise ValueError("this works with RGB images only")

    new_image= image.copy()

    leveller= Level(minv, maxv, gamma)
    levelled_data= [
        leveller.convert_and_level(data)
        for data in image.getdata()]
    new_image.putdata(levelled_data)
    return new_image
导入colorsys 类级别(对象): 定义初始值(self、minv、maxv、gamma): self.minv=minv/255.0 self.maxv=maxv/255.0 self.\u间隔=self.maxv-self.minv 自。_invgamma=1.0/gamma def新_级别(自身、值): 如果value=self.maxv:返回1.0 返回((值-self.minv)/self.\u间隔)**self.\u def转换_和_级别(自身、波段_值): h、 s,v=colorsys.rgb_至_hsv(*(i/255.0表示i带内_值)) 新水平=自我。新水平(v) 返回元组(int(255*i) 因为我 在colorsys.hsv_到_rgb(h、s、new_v))中 def液位_图像(图像,最小值=0,最大值=255,伽马值=1.0): “”“调平图像的亮度(PIL.image实例) 所有价值观≤ minv将变为0 所有价值观≥ maxv将变为255 gamma控制minv和maxv“”之间所有值的曲线 如果image.mode!=“RGB”: raise VALUERROR(“此选项仅适用于RGB图像”) new_image=image.copy() 水平仪=水平仪(最小、最大、伽马) 水平化_数据=[ 水平仪。转换水平仪和水平仪(数据) 对于image.getdata()中的数据 新的\u图像.putdata(水平化\u数据) 返回新的图像

如果有办法做RGB→使用PIL进行HSV转换(反之亦然),然后可以分为H、S、V波段,使用V波段的
.point
方法将其转换回RGB,大大加快了转换过程;但是,我还没有找到这样的方法。

这是我使用的代码。1)在HSV图像的亮度通道上,以及2)根据结果中所需的黑白像素量,进行等级设置

由于openCV使用numpy数组作为内部数据,因此可以修改代码以避免使用枕头。如果这样做,请注意openCV本机颜色空间是BGR。您必须相应地更改对cv.cvtColor()的调用

from PIL import Image
import numpy as np
import cv2 as cv

fileName = 'foo.JPG'
fileOut = 'bar.JPG'
imgPil = Image.open(fileName) 
imgCV = np.asarray(imgPil, np.uint8)
hsv = cv.cvtColor(imgCV, cv.COLOR_RGB2HSV)
h,s,v = cv.split(hsv)
ceil = np.percentile(v,95) # 5% of pixels will be white
floor = np.percentile(v,5) # 5% of pixels will be black
a = 255/(ceil-floor)
b = floor*255/(floor-ceil)
v = np.maximum(0,np.minimum(255,v*a+b)).astype(np.uint8)
hsv = cv.merge((h,s,v))
rgb = cv.cvtColor(hsv, cv.COLOR_HSV2RGB)
imgPil = Image.fromarray(rgb)
imgPil.save(fileOut)
使用此链接中的代码

#图像自动调平
def水平(数据,全部相同=0,剪辑=0):
如果data.mode不在['RGB','CMYK']中:
返回数据
##平滑缩放重新分布的直方图
lut=\u makelut(数据,全部相同,片段)
##使用直方图更新图像点
数据=数据点(lut)
返回数据
定义查找高低(lut,剪辑):
最小值=无
最大值=无
对于范围内的i(len(lut)):
如果lut[i]>剪辑:
min=i
打破
lut.reverse()
对于范围内的i(len(lut)):
如果lut[i]>剪辑:
最大值=255-i
打破
返回最小值,最大值
def_刻度(通道、最小值、最大值):
lut=[]
#赫夫尼补丁
比率=浮动(最大-最小)
如果比率==0:
比率=1
对于范围内的i(通道):
对于范围内的i(256):
值=整数((i-最小值)*(255.0/比率))
如果值<0:
值=0
如果值>255:
值=255
lut.append(值)
返回lut
def_makelut(数据,全部相同,剪辑):
直方图=数据。直方图()
lut=[]
r、 g,b,k=[],[],[],[],[]
通道=长度(直方图)/256
对于范围内的i(256):
r、 追加(直方图[i])
g、 追加(直方图[256+i])
b、 追加(直方图[512+i])
如果通道==4:
对于范围内的i(256):
k、 追加(直方图[768+i])
rmin,rmax=\u查找\u高\u低(r,剪辑)
gmin,gmax=\u find\u hi\u lo(g,clip)
bmin,bmax=_find_hi_lo(b,clip)
如果通道==4:
kmin,kmax=\u find\u hi\u lo(k)
其他:
kmin,kmax=128128
如果所有_相同==1:
最小值最大值=[rmin,gmin,bmin,kmin,rmax,gmax,bmax,kmax]
最小最大排序()
lut=_刻度(通道,最小值最大值[0],最小值最大值[-1])
其他:
r_lut=_标度(1,rmin,rmax)
g_lut=_量表(1,gmin,gmax)
b_lut=_量表(1,bmin,bmax)
如果通道==4:
k_lut=_标度(1,kmin,kmax)
lut=[]
对于范围内的i(256):
lut.append(r_lut[i])
对于范围内的i(256):
lut.append(g_lut[i])
对于范围内的i(256):
lut.append(b_lut[i])
如果通道==4:
对于范围内的i(256):
lut.append(k_lut[i])
返回lut
从PIL导入ImageEnhance、ImageDraw、Image
img=Image.open(文件路径)
img2=水平(img)

您可能会发现使用Python Wand比使用PIL更容易。魔杖基于ImageMagick,因此应该具有类似的功能。见第
# Auto leveling for image

    def levels(data, all_same = 0, clip = 0): 

        if data.mode not in ['RGB', 'CMYK']: 
            return data 

        ## get redistriputed histogram scalled smoothly
        lut = _makelut(data, all_same, clip) 

        ## update image points using histogram
        data = data.point(lut) 

        return data 

    def _find_hi_lo(lut, clip): 
        min = None 
        max = None 

        for i in range(len(lut)): 
            if lut[i] > clip: 
                min = i 
                break 

        lut.reverse() 

        for i in range(len(lut)): 
            if lut[i] > clip: 
                max = 255 - i 
                break 

        return min, max 

    def _scale(channels, min, max): 
        lut = []
        # hefny fix
        ratio = float(max-min)
        if ratio == 0:
            ratio = 1

        for i in range (channels): 
            for i in range(256): 
                value = int((i - min)*(255.0/ratio)) 
                if value < 0: 
                    value = 0 
                if value > 255: 
                    value = 255 
                lut.append(value) 

        return lut 


    def _makelut(data, all_same, clip): 

        histogram = data.histogram() 

        lut = [] 
        r, g, b, k = [], [], [], [] 

        channels = len(histogram)/256 

        for i in range(256): 
            r.append(histogram[i]) 
            g.append(histogram[256+i]) 
            b.append(histogram[512+i]) 
        if channels == 4: 
            for i in range(256): 
                k.append(histogram[768+i]) 


        rmin, rmax = _find_hi_lo(r, clip) 
        gmin, gmax = _find_hi_lo(g, clip) 
        bmin, bmax = _find_hi_lo(b, clip) 
        if channels == 4: 
            kmin, kmax = _find_hi_lo(k) 
        else: 
            kmin, kmax = 128, 128 

        if all_same == 1: 

            min_max = [rmin, gmin, bmin, kmin, rmax, gmax, bmax, kmax] 
            min_max.sort() 
            lut = _scale(channels, min_max[0], min_max[-1]) 

        else: 

            r_lut = _scale(1, rmin, rmax) 
            g_lut = _scale(1, gmin, gmax) 
            b_lut = _scale(1, bmin, bmax) 
            if channels == 4: 
                k_lut = _scale(1, kmin, kmax) 

            lut = [] 

            for i in range (256): 
                lut.append(r_lut[i]) 
            for i in range (256): 
                lut.append(g_lut[i]) 
            for i in range (256): 
                lut.append(b_lut[i]) 
            if channels == 4: 
                for i in range (256): 
                    lut.append(k_lut[i]) 

        return lut 

from PIL import ImageEnhance , ImageDraw , Image
img = Image.open(file_path)
img2 = levels(img)