实现分段线性变换,显示处理前后图像

2.产生灰度变换函数T1,使得:
0.3r r < 0.35
s = 0.105 + 2.6333(r-0.35) 0.35 ≤ r ≤ 0.65
1 + 0.3(r-1) r > 0.65
用T1对原图像rice.jpg进行处理,显示处理前、后的图像(r,s为归一化灰度)。

img

rice.jpg

img

实验仪器
Python+OpenCV


import cv2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider #调用Slider滑块控件

def set_chinese(): #使得画图时的标题可以为中文
    import matplotlib
    print("[INFO] matplotlib版本为: %s" % matplotlib.__version__)
    matplotlib.rcParams['font.sans-serif'] = ['FangSong']
    matplotlib.rcParams['axes.unicode_minus'] = False

def three_line_trans(x,x1,y1,x2,y2):
    if x1==0 or x1==x2 or x2==255:
        print("[INFO] x1={},x2{} ->调用此函数必须满足: x1≠x2且x2≠255以及x1≠0")
        return None

    #【快速算法】
    m1 = (x<x1)
    m2 = (x>x1)&(x<x2)
    m3 = (x>x2)
    output = (y1*x/x1)*m1 + (((y2-y1)/(x2-x1))*(x-x1)+y1)*m2 + (((255-y2)/(255-x2))*(x-x2)+y2)*m3

    # 3.获取分段线性函数的点集,用于绘制函数图像
    x_point = np.arange(0, 256, 1)
    cond2 = [True if (i >= x1 and i <= x2) else False for i in x_point] #!!!不能直接写x1<=x_point<=x2,否则报错。暂时不知道为什么不能双向
    y_point = (y1 / x1 * x_point) * (x_point < x1) \
              + ((y2 - y1) / (x2 - x1) * (x_point - x1) + y1) * (cond2) \
              + ((255 - y2) / (255 - x2) * (x_point - x2) + y2) * (x_point > x2)

    return output, x_point, y_point

def update_trans(val):
    # 读入4个滑动条的值
    x1, y1 = slider_x1.val, slider_y1.val
    x2, y2 = slider_x2.val, slider_y2.val
    if x1>=x2:
        x1 = x2-1
    if y1>=y2:
        y1 = y2-1
    output, x_point, y_point = three_line_trans(img_original1, x1=x1, y1=y1, x2=x2, y2=y2)
    ax3.clear()
    ax3.set_title('分段线性函数图像', fontsize=8)
    ax3.grid(True, linestyle=':', linewidth=1)
    ax3.plot([x1, x2], [y1, y2], 'ro')
    ax3.plot(x_point, y_point, 'g')

    ax4.clear()
    ax4.set_title('变换后的图像', fontsize=8)
    ax4.imshow(output, cmap='gray', vmin=0, vmax=255)

    ax5.clear()
    ax5.set_title('变换后图像直方图', fontsize=8)
    ax5.hist(output.flatten(),bins=50, density=True, color='r', edgecolor='k')
    ax5.set_xlim(0, 255)  # 设置x轴分布范围
    ax5.set_ylim(0, 0.15)  # 设置y轴分布范围
    ax5.grid(True, linestyle=':', linewidth=1)


if __name__ == '__main__':
    set_chinese()
    img_original = cv2.imread(r'Fig0316(2)(2nd_from_top).tif')
    img_original1 = cv2.cvtColor(img_original, cv2.COLOR_BGR2GRAY)


    fig = plt.figure()
    ax1 = fig.add_subplot(231)
    ax2 = fig.add_subplot(232)
    ax3 = fig.add_subplot(233)
    ax4 = fig.add_subplot(234)
    ax5 = fig.add_subplot(235)

    ax1.set_title('原始输入图片',fontsize=8)
    ax1.imshow(img_original1,cmap='gray',vmin=0,vmax=255) #官方文档:https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.imshow.html#matplotlib.axes.Axes.imshow
    ax2.set_title('原始输入图片直方图',fontsize=8)
    ax2.hist(img_original1.flatten(), bins=50, density=True, color='r', edgecolor='k') #bin属性控制直方图横条的数量, density为True则显示的是概率密度
    ax2.set_xlim(0, 255)  # 设置x轴分布范围
    ax2.set_ylim(0, 0.15)  # 设置y轴分布范围
    ax2.grid(True, linestyle=':', linewidth=1)

    plt.subplots_adjust(bottom=0.3)
    x1 = plt.axes([0.25, 0.2, 0.45, 0.03], facecolor='lightgoldenrodyellow') #控制横轴的left,bottom,width,height位置和大小
    slider_x1 = Slider(x1, '参数x1', 0.0, 255.,
                       valfmt='%.f', valinit=91, valstep=1) #slider的输入x必须是一个Axes
    slider_x1.on_changed(update_trans)

    y1 = plt.axes([0.25, 0.16, 0.45, 0.03],
                  facecolor='lightgoldenrodyellow')
    slider_y1 = Slider(y1, '参数y1', 0.0, 255.,
                       valfmt='%.f', valinit=0, valstep=1)
    slider_y1.on_changed(update_trans)

    x2 = plt.axes([0.25, 0.06, 0.45, 0.03],
                  facecolor='white')
    slider_x2 = Slider(x2, '参数x2', 0.0, 254.,
                       valfmt='%.f', valinit=138, valstep=1) #valinit表示slider的点的初始位置(即滑块的初始值)
    slider_x2.on_changed(update_trans)

    y2 = plt.axes([0.25, 0.02, 0.45, 0.03],
                  facecolor='white')
    slider_y2 = Slider(y2, '参数y2', 0.0, 255.,
                       valfmt='%.f', valinit=255, valstep=1)
    slider_y2.on_changed(update_trans)

    slider_x1.set_val(91)
    slider_y1.set_val(91)
    slider_x2.set_val(138)
    slider_y2.set_val(138)
    #plt.tight_layout()
    plt.show()

img