opencv study notes 2

Grayscale image

import cv2 #opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt#Matplotlib是RGB
%matplotlib inline 

img=cv2.imread('cat.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_gray.shape
(414, 500)
cv2.imshow("img_gray", img_gray)
cv2.waitKey(0)    
cv2.destroyAllWindows() 

HSV

  • H - Hue (dominant wavelength).
  • S - Saturation (purity/shade of color).
  • V value (intensity)
hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

cv2.imshow("hsv", hsv)
cv2.waitKey(0)    
cv2.destroyAllWindows()

b,g,r = cv2.split(hsv)
hsv_rgb = cv2.merge((r,g,b))
plt.imshow(hsv_rgb)
plt.show()

png

image threshold

ret, dst = cv2.threshold(src, thresh, maxval, type)
  • src: input image, only single-channel images can be input, usually grayscale images

  • dst: output graph

  • thresh: threshold

  • maxval: When the pixel value exceeds the threshold (or is less than the threshold, depending on the type), the value assigned

  • type: The type of binary operation, including the following 5 types: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO; cv2.THRESH_TOZERO_INV

  • cv2.THRESH_BINARY takes maxval (maximum value) for the part exceeding the threshold, otherwise takes 0

  • cv2.THRESH_BINARY_INV Inversion of THRESH_BINARY

  • cv2.THRESH_TRUNC The part greater than the threshold is set to the threshold, otherwise it remains unchanged

  • cv2.THRESH_TOZERO The part greater than the threshold is not changed, otherwise it is set to 0

  • cv2.THRESH_TOZERO_INV The inversion of THRESH_TOZERO

ret, thresh1 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_TOZERO_INV)

titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

for i in range(6):
    plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

png

Image smoothing

img = cv2.imread('lenaNoise.png')

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(img)
img_rgb = cv2.merge((r,g,b))
plt.imshow(img_rgb)
plt.show()

png

# 均值滤波
# 简单的平均卷积操作
blur = cv2.blur(img, (3, 3))

cv2.imshow('blur', blur)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(blur)
blur_rgb = cv2.merge((r,g,b))
plt.imshow(blur_rgb)
plt.show()

png

# 方框滤波
# 基本和均值一样,可以选择归一化
box = cv2.boxFilter(img,-1,(3,3), normalize=True)  #-1表示颜色通道数与之前输入的图像颜色通道数一致

cv2.imshow('box', box)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(box)
box_rgb = cv2.merge((r,g,b))
plt.imshow(box_rgb)
plt.show()

png

# 方框滤波
# 基本和均值一样,可以选择归一化,容易越界 ,即像素值大于255
box = cv2.boxFilter(img,-1,(3,3), normalize=False)  

cv2.imshow('box', box)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(box)
box_rgb = cv2.merge((r,g,b))
plt.imshow(box_rgb)
plt.show()

png

# 高斯滤波
# 高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的,即核中间像素值的权重比较大
aussian = cv2.GaussianBlur(img, (5, 5), 1)  

cv2.imshow('aussian', aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(aussian)
aussian_rgb = cv2.merge((r,g,b))
plt.imshow(aussian_rgb)
plt.show()

png

# 中值滤波
# 相当于用中值代替
median = cv2.medianBlur(img, 5)  # 中值滤波

cv2.imshow('median', median)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(median)
median_rgb = cv2.merge((r,g,b))
plt.imshow(median_rgb)
plt.show()

png

# 展示所有的
res = np.hstack((blur,aussian,median)) #横着拼接在一起
#res = np.vstack((blur,aussian,median)) #竖着拼接在一起
#print (res)
cv2.imshow('median vs average', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(res)
res_rgb = cv2.merge((r,g,b))
plt.imshow(res_rgb)
plt.show()

png

Morphology-corrosion operations

img = cv2.imread('cloudytosunny1.png')

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(img)
img_rgb = cv2.merge((r,g,b))
plt.imshow(img_rgb)
plt.show()

png

kernel = np.ones((4,4),np.uint8) 
erosion = cv2.erode(img,kernel,iterations = 1)

cv2.imshow('erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(erosion)
erosion_rgb = cv2.merge((r,g,b))
plt.imshow(erosion_rgb)
plt.show()

png

pie = cv2.imread('pie.png')

cv2.imshow('pie', pie)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(pie)
pie_rgb = cv2.merge((r,g,b))
plt.imshow(pie_rgb)
plt.show()

png

kernel = np.ones((30,30),np.uint8) 
erosion_1 = cv2.erode(pie,kernel,iterations = 1)
erosion_2 = cv2.erode(pie,kernel,iterations = 2)
erosion_3 = cv2.erode(pie,kernel,iterations = 3)
res = np.hstack((erosion_1,erosion_2,erosion_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(res)
res_rgb = cv2.merge((r,g,b))
plt.imshow(res_rgb)
plt.show()

png

Morphology-expansion operation

img = cv2.imread('cloudytosunny1.png')
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(img)
img_rgb = cv2.merge((r,g,b))
plt.imshow(img_rgb)
plt.show()

png

kernel = np.ones((5,5),np.uint8) 
sunny_erosion = cv2.erode(img,kernel,iterations = 1)

cv2.imshow('erosion', sunny_erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(sunny_erosion)
sunny_erosion_rgb = cv2.merge((r,g,b))
plt.imshow(sunny_erosion_rgb)
plt.show()

png

kernel = np.ones((5,5),np.uint8) 
sunny_dilate = cv2.dilate(sunny_erosion,kernel,iterations = 1)

cv2.imshow('dilate', sunny_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(sunny_dilate)
sunny_dilate_rgb = cv2.merge((r,g,b))
plt.imshow(sunny_dilate_rgb)
plt.show()

png

pie = cv2.imread('pie.png')

kernel = np.ones((30,30),np.uint8) 
dilate_1 = cv2.dilate(pie,kernel,iterations = 1)
dilate_2 = cv2.dilate(pie,kernel,iterations = 2)
dilate_3 = cv2.dilate(pie,kernel,iterations = 3)
res = np.hstack((dilate_1,dilate_2,dilate_3))
cv2.imshow('res', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(res)
res_rgb = cv2.merge((r,g,b))
plt.imshow(res_rgb)
plt.show()

png

Opening and closing operations

# 开:先腐蚀,再膨胀
img = cv2.imread('cloudytosunny1.png')

kernel = np.ones((5,5),np.uint8) 
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

cv2.imshow('opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(opening)
opening_rgb = cv2.merge((r,g,b))
plt.imshow(opening_rgb)
plt.show()

png

# 闭:先膨胀,再腐蚀
img = cv2.imread('cloudytosunny1.png')

kernel = np.ones((5,5),np.uint8) 
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

cv2.imshow('closing', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()

b,g,r = cv2.split(closing)
closing_rgb = cv2.merge((r,g,b))
plt.imshow(closing_rgb)
plt.show()


png

Gradient operation

# 梯度=膨胀-腐蚀
pie = cv2.imread('pie.png')
kernel = np.ones((7,7),np.uint8) 
dilate = cv2.dilate(pie,kernel,iterations = 5)
erosion = cv2.erode(pie,kernel,iterations = 5)

res = np.hstack((dilate,erosion))

b,g,r = cv2.split(res)
res_rgb = cv2.merge((r,g,b))
plt.imshow(res_rgb)
plt.show()

png

gradient = cv2.morphologyEx(pie, cv2.MORPH_GRADIENT, kernel)

b,g,r = cv2.split(gradient)
gradient_rgb = cv2.merge((r,g,b))
plt.imshow(gradient_rgb)
plt.show()

png

Top hat and black hat

  • Top hat = original input - result of open operation
  • Black hat = closed operation - original input
#礼帽
img = cv2.imread('cloudytosunny1.png')
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)

b,g,r = cv2.split(tophat)
tophat_rgb = cv2.merge((r,g,b))
plt.imshow(tophat_rgb)
plt.show()

png

#黑帽
img = cv2.imread('cloudytosunny1.png')
blackhat  = cv2.morphologyEx(img,cv2.MORPH_BLACKHAT, kernel)

b,g,r = cv2.split(blackhat)
blackhat_rgb = cv2.merge((r,g,b))
plt.imshow(blackhat_rgb)
plt.show()

png

Image gradient-Sobel operator

Please add image description

img = cv2.imread('pie.png',cv2.IMREAD_GRAYSCALE)

# b,g,r = cv2.split(img)
# img_rgb = cv2.merge((r,g,b))
plt.imshow(img)
plt.show()

cv2.imshow("img",img)
cv2.waitKey()
cv2.destroyAllWindows()

png

dst = cv2.Sobel(src, ddepth, dx, dy, ksize)

  • ddepth: depth of image
  • dx and dy represent the horizontal and vertical directions respectively
  • ksize is the size of the Sobel operator
def cv_show(img,name):
    b,g,r = cv2.split(img)
    img_rgb = cv2.merge((r,g,b))
    plt.imshow(img_rgb)
    plt.show()
def cv_show1(img,name):
    plt.imshow(img)
    plt.show()
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)

cv_show1(sobelx,'sobelx')

png

From white to black, it is a positive number, from black to white, it is a negative number. All negative numbers will be truncated to 0, so the absolute value must be taken.

sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
cv_show1(sobelx,'sobelx')

png

sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)  
cv_show1(sobely,'sobely')

png

Calculate x and y separately, then sum

sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show1(sobelxy,'sobelxy')

png

It is not recommended to calculate directly

sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy) 
cv_show1(sobelxy,'sobelxy')

png

img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
cv_show1(img,'img')

png

img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show1(sobelxy,'sobelxy')

png

img = cv2.imread(‘lena.jpg’,cv2.IMREAD_GRAYSCALE)

sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_show(sobelxy,‘sobelxy’)

Image gradient - Scharr operator

Please add image description

Image gradient-laplacian operator

Please add image description

#不同算子的差异
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)   
sobely = cv2.convertScaleAbs(sobely)  
sobelxy =  cv2.addWeighted(sobelx,0.5,sobely,0.5,0)  

scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)   
scharry = cv2.convertScaleAbs(scharry)  
scharrxy =  cv2.addWeighted(scharrx,0.5,scharry,0.5,0) 

laplacian = cv2.Laplacian(img,cv2.CV_64F) #一般不会单独使用,会跟其他方法联合使用
laplacian = cv2.convertScaleAbs(laplacian)   

res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show1(res,'res')

png

img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
cv_show1(img,'img')

png

Canny edge detection

    1.    使用高斯滤波器,以平滑图像,滤除噪声。
      
    1.    计算图像中每个像素点的梯度强度和方向。
      
    1.    应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
      
    1.    应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
      
    1.    通过抑制孤立的弱边缘最终完成边缘检测。
      
1: Gaussian filter

png

2: Gradient and direction

png

3: Non-maximum suppression

png

png

4: Double threshold detection

png

img=cv2.imread("lena.jpg",cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,80,150)
v2=cv2.Canny(img,50,100)

res = np.hstack((v1,v2))
cv_show1(res,'res')

png

img=cv2.imread("car.png",cv2.IMREAD_GRAYSCALE)

v1=cv2.Canny(img,120,250)
v2=cv2.Canny(img,50,100)

res = np.hstack((v1,v2))
cv_show1(res,'res')

png

image pyramid

  • Gaussian Pyramid
  • Laplace's Pyramid

png

Gaussian Pyramid: Downsampling Method (Downsizing)

png

Gaussian Pyramid: Upsampling Method (Zoom-Up)

png

img=cv2.imread("AM.png")
cv_show(img,'img')
print (img.shape)

png

(442, 340, 3)
up=cv2.pyrUp(img)
cv_show(up,'up')
print (up.shape)

png

(884, 680, 3)
down=cv2.pyrDown(img)
cv_show(down,'down')
print (down.shape)

png

(221, 170, 3)
up2=cv2.pyrUp(up)
cv_show(up2,'up2')
print (up2.shape)

png

(1768, 1360, 3)
up=cv2.pyrUp(img)
up_down=cv2.pyrDown(up)
cv_show(up_down,'up_down')

png

cv_show(np.hstack((img,up_down)),'up_down')

png

up=cv2.pyrUp(img)
up_down=cv2.pyrDown(up)
cv_show(img-up_down,'img-up_down')

png

Laplace's Pyramid

png

down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show(l_1,'l_1')

png

image outline

cv2.findContours(img,mode,method)

mode:Contour retrieval mode

  • RETR_EXTERNAL: Only retrieve the outermost contour;
  • RETR_LIST: Retrieve all contours and save them to a linked list;
  • RETR_CCOMP: Retrieve all contours and organize them into two layers: the top layer is the outer boundary of each part, and the second layer is the boundary of the hole;
  • RETR_TREE: Retrieve all contours and reconstruct the entire hierarchy of nested contours;

method:Contour approximation method

  • CHAIN_APPROX_NONE: Output contours in Freeman chain code, all other methods output polygons (sequences of vertices).
  • CHAIN_APPROX_SIMPLE: Compress the horizontal, vertical and oblique parts, that is, the function only retains their end points.

png

For higher accuracy, use binary images.

img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv_show1(thresh,'thresh')

png

binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

Draw outline

cv_show(img,'img')

png

#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res,'res')

png

draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
cv_show(res,'res')

png

Contour features
cnt = contours[0]
#面积
cv2.contourArea(cnt)
8500.5
#周长,True表示闭合的
cv2.arcLength(cnt,True)
437.9482651948929
contour approximation

png

img = cv2.imread('contours2.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]

draw_img = img.copy()
res = cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show(res,'res')

png

epsilon = 0.1*cv2.arcLength(cnt,True) 
approx = cv2.approxPolyDP(cnt,epsilon,True)

draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,'res')

png

bounding rectangle

img = cv2.imread('contours.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')

png

area = cv2.contourArea(cnt)
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h
extent = float(area) / rect_area
print ('轮廓面积与边界矩形比',extent)
轮廓面积与边界矩形比 0.5154317244724715

circumscribed circle

(x,y),radius = cv2.minEnclosingCircle(cnt) 
center = (int(x),int(y)) 
radius = int(radius) 
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,'img')

png

Fourier transform

We live in a world of time. We get up at 7:00 in the morning to have breakfast, go to the subway at 8:00 and start work at 9:00. . . Using time as a reference is time domain analysis.

But in the frequency domain everything is stationary!

https://zhuanlan.zhihu.com/p/19763358

The role of Fourier transform

  • High frequency: gray components that change drastically, such as boundaries

  • Low frequency: slowly changing gray components, such as a sea

filter

  • Low-pass filter: only retains low frequencies, which will blur the image

  • High-pass filter: only retaining high frequencies will enhance image details

  • The main ones in opencv are cv2.dft() and cv2.idft(). The input image needs to be converted into np.float32 format first.

  • The part with frequency 0 in the obtained result will be in the upper left corner, and usually needs to be converted to the center position, which can be achieved through shift transformation.

  • The result returned by cv2.dft() is dual-channel (real part, imaginary part), and usually needs to be converted into an image format to display (0,255).

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

img = cv2.imread('lena.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
# 得到灰度图能表示的形式
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

png

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

img = cv2.imread('lena.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置

# 低通滤波
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])

plt.show()                

png

img = cv2.imread('lena.jpg',0)

img_float32 = np.float32(img)

dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = img.shape
crow, ccol = int(rows/2) , int(cols/2)     # 中心位置

# 高通滤波
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0

# IDFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Result'), plt.xticks([]), plt.yticks([])

plt.show()    

png


Guess you like

Origin blog.csdn.net/weixin_41756645/article/details/125461177