Numpy,Python中的“拉伸”直方图(级别)

时间:2019-04-07 17:47:19

标签: python numpy image-processing

我有一个灰度图像,其背景为0-255色阶,是中白色,平均像素色值为246;前景是灰色,平均像素颜色值为186。

我想将246以上的每个像素“偏移”到255,将186以下的每个像素“偏移”到零,并“拉伸”它们之间的所有内容。是否有任何现成的算法/过程以numpy或python来执行此操作,还是必须“手动”计算新的水平/直方图(如我到目前为止所做的那样)?

这等效于在Gimp或Photoshop中,打开级别窗口,并分别用白色和黑色吸管选择要创建白色的亮区域和要创建黑色的较暗区域:应用程序修改了级别/直方图(“拉伸”所选点之间的值)。

我正在尝试的一些图像:

page after page shadow elimination Sampled colours Result

2 个答案:

答案 0 :(得分:1)

这是一种方法-

def stretch(a, lower_thresh, upper_thresh):
    r = 255.0/(upper_thresh-lower_thresh+2) # unit of stretching
    out = np.round(r*(a-lower_thresh+1)).astype(a.dtype) # stretched values
    out[a<lower_thresh] = 0
    out[a>upper_thresh] = 255
    return out

根据OP,设置的标准为:

  • 246上方的每个像素“移动”到255,因此247及以上的像素应变为255

  • 186zero以下的每个像素,因此185及以下的像素应变为0

  • 因此,基于上述两个要求,186应该大于0,依此类推,直到246小于255

或者,我们也可以使用np.where使它更紧凑-

def stretch(a, lower_thresh, upper_thresh):
    r = 255.0/(upper_thresh-lower_thresh+2) # unit of stretching
    out = np.round(r*np.where(a>=lower_thresh,a-lower_thresh+1,0)).clip(max=255)
    return out.astype(a.dtype)

样品运行-

# check out first row input, output for variations
In [216]: a
Out[216]: 
array([[186, 187, 188, 246, 247],
       [251, 195, 103,   9, 211],
       [ 21, 242,  36,  87,  70]], dtype=uint8)

In [217]: stretch(a, lower_thresh=186, upper_thresh=246)
Out[217]: 
array([[  4,   8,  12, 251, 255], 
       [255,  41,   0,   0, 107],
       [  0, 234,   0,   0,   0]], dtype=uint8)

答案 1 :(得分:1)

如果您的图片是uint8并且具有典型的图片大小,则一种有效的方法是设置查找表:

L, H = 186, 246
lut = np.r_[0:0:(L-1)*1j, 0.5:255.5:(H-L+3)*1j, 255:255:(255-H-1)*1j].astype('u1')

# example
from scipy.misc import face
f = face()

rescaled = lut[f]

对于较小的图像,直接转换的速度更快(在我的设置中,它跨越约100,000个灰度像素):

fsmall = (f[::16, ::16].sum(2)//3).astype('u1')

slope = 255/(H-L+2)
rescaled = ((1-L+0.5/slope+fsmall)*slope).clip(0, 255).astype('u1')