执行与ImageMagick'相同的操作;s"-级别“;在python/PIL中?
我想在python中调整图像的颜色级别。我可以使用任何可以轻松安装在Ubuntu桌面上的python库。我想做与ImageMagick的执行与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函数应该可以满足您的需要 有两点需要注意: 速度肯
-级别()相同的事情。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)