第2章 图像变换

写得比较粗错,详解后续跟上。

第2章 图像变换

图像变换主要通过调节像素数值,调节色彩明暗度,显示图像细节,方便人眼观察。图像变换的本质是调节像素分布。本节主要讲述常用的线性变换和非线性变换。
在这里插入图片描述

本节要点:

  • 反色变换
  • 线性变换
  • 对数变换
  • gamma变换
  • 分段线性变换

2.1 反色变换

反色变换是一种非常简单实用的线性变换,适用于过暗或者过亮的图片,通过反色,使得暗色区域变得明亮,凸显图像中关注的部分。

2.1.1 基本原理

反色变换的基本原理将灰度图像素值翻转,即用图像最大值减去所有的像素值,使黑白色发生翻转。

2.1.2 源码

反色变换的步骤:

  • 求取图像的最大值
  • 最大值减去原像素值
# 2.1 反色变换,可以让暗色区域变亮,

def col_invert(img):
    max_p = np.max(img)
    table = [max_p-i for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img,table)


2.1.3 样例

在图像变换过程中先计算每个像素值变换后的数值,并存放在table变量中,然后用cv2.LUT()函数在table中查找像素变换后对应的数值,这样减少重复计算,加快运算速度。

import cv2
import numpy as np
import matplotlib.pyplot as plt

def col_invert(img):
    max_p = np.max(img)
    table = [max_p-i for i in range(256)]  # 把像素变换后的值放入table中,方便cv2.LUT()查找。
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img,table)   # cv2.LUT()是批量对像素进行查找和扫描,节省重复计算。

img = cv2.imread('f1.png',0)
img1 = col_invert(img)

plt.subplot(121)
plt.title('img')
plt.imshow(img,'gray')
plt.subplot(122)
plt.title('img1')
plt.imshow(img1,'gray')
plt.show()

在这里插入图片描述

2.2 线性变换

图像通过线性变换可以增加图片的对比度,调节图像的亮度。
在这里插入图片描述

2.2.1 基本原理

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,1,100)
y_05 = 0.5*x
y_1 = x
y_2 = 2*x
plt.plot(x,y_05,'-',label = '0.5')
plt.plot(x,y_1,'--',label = '1')
plt.plot(x,y_2,'-.',label = '2')
plt.ylim(0,1)
plt.xlim(0,1)
plt.legend()
plt.title('line_convert')
plt.scatter(0.2,0.4)
plt.scatter(0.4,0.8)
plt.scatter(0.2,0.1)
plt.scatter(0.4,0.2)

plt.text(0.2,0.45,'A1(0.2,0.4)')
plt.text(0.4,0.85,'A2(0.4,0.8)')
plt.text(0.2,0.15,'B1(0.2,0.1)')
plt.text(0.4,0.25,'B2(0.4,0.2)')

img1 = c*img+b

c:调节像素映射后的区间,c大于1,变换后的区间就越大,数据越离散;反之,c小于1,像素变换后就越聚集,颜色对比度就越小。
b:决定像素直方图的中心位置,b值越大,图像就越亮,反之,越暗。

2.2.2 源码

def line_convert(img,c,b):
    table = [c * i+b for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)

2.2.3 样例

import cv2
import numpy as np
import matplotlib.pyplot as plt

def line_convert(img,c,b):
    table = [c * i+b for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)

img = cv2.imread('f4.png',1)
img1 = line_convert(img,3,1)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
plt.show()

在这里插入图片描述

加入滚动条


import cv2
import numpy as np
from matplotlib.widgets import Slider,Button,RadioButtons
import matplotlib.pyplot as plt
from PIL import Image   # pip install pillow


def set_chinese():
    import matplotlib as mp
    mp.rcParams['font.sans-serif']=['SimHei']
    mp.rcParams['axes.unicode_minus'] = False

def line_convert(img,c,b):
    table = [c * i+b for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)

def update_para(val):
    c = slider_1.val
    b = slider_2.val   # 得到滑动条数值
    img1 = line_convert(img,c,b)
    ax2.set_title('c=%f,c=%f'%(c,b))
    ax2.imshow(img1[..., ::-1], vmin=0, vmax=255)


if __name__ == '__main__':
    set_chinese()
    img = cv2.imread('f4.png',1)   # base = 86

    fig = plt.figure()
    ax0 = fig.add_subplot(121)
    ax0.set_title('原图')
    ax0.imshow(img[...,::-1],vmin=0,vmax=255)

    ax2 = fig.add_subplot(122)  # 设置第二幅图

    # 添加滑动条
    plt.subplots_adjust(bottom=0.3)   # [0.25,0.1,0.45,0.03]
    s1 = plt.axes([0.25,0.1,0.55,0.03],facecolor='lightgoldenrodyellow')
    slider_1 = Slider(s1,'c',0.,10.,valfmt='%.f',valinit=5.0,valstep=0.5) # 0.0,2.0 是参数取值范围
    # 把监控到的gamma变换传入update_gamma函数中去
    slider_1.on_changed(update_para)

    s2 = plt.axes([0.25, 0.16, 0.55, 0.03], facecolor='lightgoldenrodyellow')
    slider_2 = Slider(s2, 'b', 0., 255., valfmt='%.f', valinit=0, valstep=1)
    slider_2.on_changed(update_para)

    slider_1.reset()
    slider_1.set_val(1)

    slider_2.reset()
    slider_2.set_val(1)

2.3 对数变换

对图像进行对数变换,可以压缩图像像素的取值范围,使得图像以肉眼可分辨的灰度值显示出来,即图像经过对数变换可以显示更多的细节。
在这里插入图片描述

暗色区域提升区分度
img = np.array([[0,  5, 10, 15, 20, 25, 30, 35, 40, 45, 50,255],
[0,  5, 10, 15, 20, 25, 30, 35, 40, 45, 50,255],
                [0,  5, 10, 15, 20, 25, 30, 35, 40, 45, 50,255]],dtype=np.uint8)
plt.imshow(img,'gray',vmin=0,vmax=255)
plt.hist(img.flatten(),bins=50,density=True,color='r',edgecolor='k')


def log(base, x):
    return np.log(x) / np.log(base + 1)


def log_convert(img, base, c):
    table = [c * log(base, 1 + (base) * i / 255) * 255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)
img1 = log_convert(img,80,1)
plt.imshow(img1,'gray',vmin=0,vmax=255)
plt.hist(img1.flatten(),bins=50,density=True,color='r',edgecolor='k')

plt.subplot(221)
plt.title('origin')
plt.imshow(img,'gray',vmin=0,vmax=255)
plt.subplot(222)
plt.title('log_convert')
plt.imshow(img1,'gray',vmin=0,vmax=255)
plt.subplot(223)
plt.title('origin_hist')
plt.hist(img.flatten(),bins=50,density=True,color='r',edgecolor='k')
plt.subplot(224)
plt.title('log_convert_hist')
plt.hist(img1.flatten(),bins=50,density=True,color='r',edgecolor='k')

img1 = np.array([[190,  38,  74,  95, 111, 124, 134, 142, 150, 157, 163,   0],
       [190,  38,  74,  95, 111, 124, 134, 142, 150, 157, 163,   0],
       [190,  38,  74,  95, 111, 124, 134, 142, 150, 157, 163,   0]],
      dtype=uint8)

在这里插入图片描述

亮色区区分度降低
img=np.array([[  0, 204, 209, 214, 219, 224, 229, 234, 239, 244, 249, 254],
       [  0, 204, 209, 214, 219, 224, 229, 234, 239, 244, 249, 254],
       [  0, 204, 209, 214, 219, 224, 229, 234, 239, 244, 249, 254]],
      dtype=uint8)
      
def log(base, x):
    return np.log(x) / np.log(base + 1)


def log_convert(img, base, c):
    table = [c * log(base, 1 + (base) * i / 255) * 255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)
img1 = log_convert(img,80,1)
plt.imshow(img1,'gray',vmin=0,vmax=255)
plt.hist(img1.flatten(),bins=50,density=True,color='r',edgecolor='k')

plt.subplot(221)
plt.title('origin')
plt.imshow(img,'gray',vmin=0,vmax=255)
plt.subplot(222)
plt.title('log_convert')
plt.imshow(img1,'gray',vmin=0,vmax=255)
plt.subplot(223)
plt.title('origin_hist')
plt.hist(img.flatten(),bins=50,density=True,color='r',edgecolor='k')
plt.subplot(224)
plt.title('log_convert_hist')
plt.hist(img1.flatten(),bins=50,density=True,color='r',edgecolor='k')

img1 = np.array([[190, 243, 245, 246, 247, 249, 250, 251, 252, 254, 255,   0],
       [190, 243, 245, 246, 247, 249, 250, 251, 252, 254, 255,   0],
       [190, 243, 245, 246, 247, 249, 250, 251, 252, 254, 255,   0]],
      dtype=uint8)

在这里插入图片描述

def log(base,x):
    return np.log(1+base*x)/np.log(base+1)


x = np.linspace(0,1,100)
y = 1*x
y_1 = log(1,x)
y_10 = log(10,x)
y_30 = log(30,x)
y_100 = log(100,x)
y_300 = log(300,x)
plt.plot(x,y,label = 'origin')
plt.plot(x,y_1,label = 'b=1')
plt.plot(x,y_10,label = 'b=10')
plt.plot(x,y_30,label = 'b=30')
plt.plot(x,y_100,label = 'b=100')
plt.plot(x,y_300,label = 'b=300')

plt.ylim(0,1)
plt.xlim(0,1)
plt.legend()
plt.title('log_line')
plt.xlabel('input intensity level')
plt.ylabel('output intensity level')
plt.text(0.35,0.350,'origin')
plt.text(0.32,0.43,'b=1')
plt.text(0.23,0.52,'b=10')
plt.text(0.2,0.6,'b=30')
plt.text(0.18,0.66,'b=100')
plt.text(0.16,0.75,'b=300')
plt.show()

2.3.1 基本原理


img1 = c*log_{base+1}(1+base*img/255)*255

2.3.2 源码


import cv2
import numpy as np
import matplotlib.pyplot as plt

def log(base,x):
    return np.log(x)/np.log(base+1)

def log_convert(img,base,c):
    table = [c*log(base,(1+i)/255)*255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img,table)

2.3.3 样例

import cv2
import numpy as np
import matplotlib.pyplot as plt

def log(base,x):
    return np.log(x)/np.log(base+1)
    
def log_convert(img,base,c):
    table = [c*log(base,1+(base)*i/255)*255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img,table)


img = cv2.imread('yejing.png',1)
img1 = log_convert(img,80,0.9)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
plt.show()

在这里插入图片描述

加入滚动条
import cv2
import numpy as np
from matplotlib.widgets import Slider,Button,RadioButtons
import matplotlib.pyplot as plt
from PIL import Image   # pip install pillow


def set_chinese():
    import matplotlib as mp
    mp.rcParams['font.sans-serif']=['SimHei']
    mp.rcParams['axes.unicode_minus'] = False


def log(base, x):
    return np.log(x) / np.log(base + 1)

def log_convert(img, base, c=1):
    table = [c * log(base, 1 + (base) * i / 255) * 255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)

def update_gamma(val):
    base = slider1.val # 得到滑动条数值
    img1 = log_convert(img, base, c=1)
    ax2.set_title('base=%f'%(base))
    ax2.imshow(img1[..., ::-1], vmin=0, vmax=255)


if __name__ == '__main__':
    set_chinese()
    img = cv2.imread('2.png',1)

    fig = plt.figure()
    ax0 = fig.add_subplot(121)
    ax0.set_title('原图')
    ax0.imshow(img[...,::-1],vmin=0,vmax=255)

    ax2 = fig.add_subplot(122)  # 设置第二幅图

    # 添加滑动条
    plt.subplots_adjust(bottom=0.3)   # [0.25,0.1,0.45,0.03]
    s1 = plt.axes([0.25,0.1,0.45,0.03],facecolor='lightgoldenrodyellow')
    slider1 = Slider(s1,'base',0.,200.,valfmt='%.f',valinit=50.0,valstep=2) # 0.0,2.0 是参数取值范围
    # 把监控到的gamma变换传入update_gamma函数中去
    slider1.on_changed(update_gamma)
    slider1.reset()
    slider1.set_val(1)

在这里插入图片描述

2.4 gamma变换

在这里插入图片描述

def gamma_line(x,r):
    return x**r

x = np.linspace(0,1,100)
y = gamma_line(x,1)
y_1 = gamma_line(x,2.5)
y_2 = gamma_line(x,0.4)

plt.plot(x,y,'-',label = 'r=1')
plt.plot(x,y_1,'--',label = 'r=2.5')
plt.plot(x,y_2,'-.',label = 'r=0.4')


plt.ylim(0,1)
plt.xlim(0,1)
plt.legend()
plt.title('gamma_line')
plt.xlabel('input intensity level')
plt.ylabel('output intensity level')
plt.show()

2.4.1 基本原理

步骤:
· 归一化
·
·
·


img1 = c*(\frac{img+\epsilon}{255} )^\gamma*255+r

2.4.2 源码


def gamma_convert(img,c,r):
    table = [c * ((i+0.1)/255)**r * 255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)

2.4.3 样例

import cv2
import numpy as np
import matplotlib.pyplot as plt

def gamma_convert(img,c,r):
    table = [c * ((i+0.1)/255)**r * 255 for i in range(256)]
    table = np.round(np.array(table)).astype(np.uint8)
    return cv2.LUT(img, table)

img = cv2.imread('beijing2.png',1)
img1 = gamma_convert(img,1,0.5)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])
plt.show()

在这里插入图片描述

使用滑动条操作

import cv2
import numpy as np
from matplotlib.widgets import Slider,Button,RadioButtons
import matplotlib.pyplot as plt
from PIL import Image   # pip install pillow


def set_chinese():
    import matplotlib as mp
    mp.rcParams['font.sans-serif']=['SimHei']
    mp.rcParams['axes.unicode_minus'] = False

def gamma_convert(img,gamma,eps=0):
    return (255*(((img+eps)/255.)**gamma)).astype(np.uint8)

def update_gamma(val):
    gamma = slider1.val # 得到滑动条数值
    img1 = gamma_convert(img, gamma, eps=0)
    ax2.set_title('gamma=%f'%(gamma))
    ax2.imshow(img1[..., ::-1], vmin=0, vmax=255)


if __name__ == '__main__':
    set_chinese()
    img = cv2.imread('luna_baoguang.png',1)

    fig = plt.figure()
    ax0 = fig.add_subplot(121)
    ax0.set_title('露娜')
    ax0.imshow(img[...,::-1],vmin=0,vmax=255)

    ax2 = fig.add_subplot(122)  # 设置第二幅图

    # 添加滑动条
    plt.subplots_adjust(bottom=0.3)
    s1 = plt.axes([0.25,0.1,0.55,0.03],facecolor='lightgoldenrodyellow')
    slider1 = Slider(s1,'para :gamma',0.0,10.0,valfmt='%.f',valinit=5.0,valstep=0.1) # 0.0,2.0 是参数取值范围
    # 把监控到的gamma变换传入update_gamma函数中去
    slider1.on_changed(update_gamma)
    slider1.reset()
    slider1.set_val(1)

2.5 分段线性变换

在这里插入图片描述

2.5.1 基本原理



2.5.2 源码

def three_line_convert(img,x1,y1,x2,y2):
    if x1==x2 or x2 == 255:
        return None
    m1 = (img<x1)
    m2 = (x1<=img)&(img<=x2)
    m3 = (img>x2)

    img1 = (y1/x1*img)*m1+((y2-y1)/(x2-x1)*(img-x1)+y1)*m2+((255-y2)/(255-x2)*(img-x2)+y2)*m3
    img1 = img1.astype(np.uint8)
    return img1

2.5.3 样例

import cv2
import numpy as np
import matplotlib.pyplot as plt

def three_line_convert(img,x1,y1,x2,y2):
    if x1==x2 or x2 == 255:
        return None
    m1 = (img<x1)
    m2 = (x1<=img)&(img<=x2)
    m3 = (img>x2)

    img1 = (y1/x1*img)*m1+((y2-y1)/(x2-x1)*(img-x1)+y1)*m2+((255-y2)/(255-x2)*(img-x2)+y2)*m3
    img1 = img1.astype(np.uint8)
    return img1

img = cv2.imread('fen3.png',1)
img1 = three_line_convert(img,36,76,178,228)
plt.subplot(121)
plt.title('img')
plt.imshow(img[...,::-1])
plt.subplot(122)
plt.title('img1')
plt.imshow(img1[...,::-1])

在这里插入图片描述

加入滚动条


import cv2
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider


def three_line_convert(img,x1,y1,x2,y2):
    if x1==x2 or x2 == 255:
        return None
    m1 = (img<x1)
    m2 = (x1<=img)&(img<=x2)
    m3 = (img>x2)

    img1 = (y1/x1*img)*m1+((y2-y1)/(x2-x1)*(img-x1)+y1)*m2+((255-y2)/(255-x2)*(img-x2)+y2)*m3
    # 绘制函数图像
    x_point = np.arange(0,256,1)
    cond2 = [True if(i>=x1 and i<=x2) else False for i in x_point]
    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 img1,x_point,y_point

def update_trans(val):
    # 1 读入滑动条的值
    x1,y1 = slider_x1.val,slider_y1.val
    x2, y2 = slider_x2.val, slider_y2.val
    # 2 执行分段线性变换
    img1,x_point,y_point = three_line_convert(img,x1,y1,x2,y2)
    img1 = img1.astype(np.uint8)
    # 3 显示变换结果
    ax2.clear()
    ax2.set_title('result',fontsize=8)
    ax2.imshow(img1[...,::-1],vmin=0,vmax=255)
    # 4 绘制函数
    ax3.clear()
    ax3.annotate('(%d,%d)'%(x1,y1),xy=(x1,y1),xytext=(x1-15, y1+15))
    ax3.annotate('(%d,%d)'%(x2,y2), xy=(x2,y2), xytext=(x2+15, y2-15))
    ax3.set_title('fun', fontsize=8)
    ax3.grid(True,linestyle=':',linewidth=1)
    ax3.plot([x1,x2],[y1,y2],'ro')
    ax3.plot(x_point, y_point, 'g')
    # 显示变换后的直方图
    ax5.clear()
    ax5.grid(True,linestyle=':',linewidth=1)
    ax5.set_title('hist',fontsize=8)
    ax5.set_xlim(0,255)
    ax5.set_ylim(0, 0.06)
    ax5.hist(img1[...,::-1].flatten(),bins=50,density=True,color='r',edgecolor='k')


img = cv2.imread('hua.png',1)  # [x1,y1,x2,y2] [36,76,178,228]
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('origin',fontsize=8)
ax1.imshow(img[...,::-1],vmin=0,vmax=255)

ax4.grid(True,linestyle=':',linewidth=1)
ax4.set_title('origin indensity',fontsize=8)
ax4.set_xlim(0,255)
ax4.set_ylim(0,0.06)
ax4.hist(img[...,0].flatten(),bins=50,density=True,color='r',edgecolor='k')

plt.subplots_adjust(bottom=0.3)
x1 = plt.axes([0.25,0.20,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_x1 = Slider(x1,'Para_x1',0.,255.,valfmt='%.f',valinit=100,valstep=1)
slider_x1.on_changed(update_trans)

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

x2 = plt.axes([0.25,0.1,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_x2 = Slider(x2,'Para_x2',0.,255.,valfmt='%.f',valinit=100,valstep=1)
slider_x2.on_changed(update_trans)

y2 = plt.axes([0.25,0.05,0.45,0.03],facecolor = 'lightgoldenrodyellow')
slider_y2 = Slider(y2,'Para_y2',0.,255.,valfmt='%.f',valinit=0,valstep=1)
slider_y2.on_changed(update_trans)


在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数字图像处理中的Z变换是一种用于表示和分析离散信号系统的重要工具。第二中介绍了Z变换的结构导图,用于说明Z变换的不同部分和它们之间的关系。 Z变换结构导图主要由四个组成部分组成:输入序列、系统函数、输出序列和单位延迟单元。输入序列是指需要进行Z变换的离散信号的序列,它可以是离散时间信号或者离散空间信号。系统函数是描述系统输出和输入之间关系的数学函数,它表示了离散系统对输入信号做出的响应。输出序列是经过系统函数处理后的结果序列,它表示了系统对输入信号的影响。单位延迟单元是指将输入序列从一个时间或空间位置移动到下一个时间或空间位置的操作,它可以用于模拟信号传播的时间或空间延迟。 在Z变换结构导图中,输入序列和单位延迟单元通过系统函数连接到输出序列。通过改变系统函数的形式和参数,可以实现不同类型的数字信号处理操作,例如滤波、变换等。Z变换结构导图的目的是帮助人们理解Z变换在数字信号处理中的应用,以及各部分之间的相互作用。 总而言之,Z变换结构导图是数字图像处理中用于表示和分析离散信号系统的工具,它由输入序列、系统函数、输出序列和单位延迟单元组成。通过改变系统函数的形式和参数,可以实现不同类型的数字信号处理操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值