您的位置:首页 > 编程语言 > Python开发

数字图像处理python基础--图片读入显示/图像的逻辑运算/缩放/旋转翻转平移/代数运算/二值化

2020-06-03 06:06 519 查看

数字图像处理基础

  • 图像的逻辑运算
  • 图像缩放
  • 图像的旋转与翻转
  • 图像的平移
  • 图像的代数运算
  • 图像的位运算+掩膜
  • 简单二值化
  • 大津阈值二值化
  • 一、基本操作

    图片的读入与显示

    pillow

    使用pillow的image读入,然后显示

    from PIL import Image
    
    lina= Image.open('lina.jpg')
    lina.show()

    转为灰度图,并且保存

    graylina= lina.convert('L')
    graylina.save('graylina.jpg')
    graylina.show()

    matplotlib

    2.使用matplotlib显示
    一个画布中显示多张图片

    from PIL import Image #导入PIL库的Image类
    import matplotlib.pyplot as plt
    lina= Image.open('lina.jpg') #读取图像文件
    iu =Image.open('iu.jpg')
    plt.subplot(121)
    plt.imshow(lina)
    plt.subplot(122)
    plt.imshow(iu)
    plt.show()


    一个plt.show()就会显示一张画布。
    注意:
    1.解决中文显示异常的方法
    plt的图注,如果是中文的话,前面要加一下代码
    2.plt.title()中的参数,如果想把标题移动上下是y=,左右是x=,上+下-
    更多title()详见
    3.plt.figure()的功能类似于matlab中的figure(1)
    在图像显示之前用这个,新建一张画布,一个程序中可以新建多张画布,最后只需要使用一个plt.show()即可
    plt.figure(figsize=(18,10))还可以规定图片的大小

    https://blog.csdn.net/helunqu2017/article/details/78659490/

    #解决中文显示问题
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    cv2

    cv2 读入并且显示图片

    lina = cv2.imread('lina.jpg')
    cv2.imshow('lina',lina)

    cv2以灰度图读入
    后面加了一个0,以灰度形式加载图片,默认是1,以彩色图片形式加载

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

    或者,BGR转为GRAY

    img = cv2.imread('lina.jpg')
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    注意:

    1. cv2读入的图片的格式是BGR,但是如果用pit去显示图片,那么就应该转换成RGB
      转换方法一:
    lina=lina[:,:,[2,1,0]] 将BGR转换成RGB

    转换方法二:

    lina_BGR = cv2.imread('lina.jpg')
    lina = cv2.cvtColor(lina_BGR,cv2.COLOR_BGR2RGB) #将B#将BGR转换成RGB

    更推荐方法二,每次cv2.imread()之后就顺便cvtColor
    如果后续要用plt.subplot()在一个画布上显示多幅图,那么就要用到这个。

    2.如果用cv2 的方法在一个画布上显示多张图,那么这些图片的size应该相同(更推荐用plt.subplot())

    imgs = np.hstack([small_lina1,small_lina2,small_lina3])
    cv.imshow("small", imgs)

    图像的逻辑运算

    A为128128的矩阵,其中行坐标40到67,列坐标60到100之间的区域为1;B为128128的矩阵,其中行坐标50到80,列坐标40到70之间的区域为1;完成两个规定矩阵A和B的“与/或/非运算”。

    import numpy as np
    import matplotlib.pyplot as plt
    A=np.zeros((128,128),dtype=int)
    A[40:67,60:100]=1
    B=np.zeros((128,128),dtype=int)
    B[50:80,40:70]=1
    #C = A & B
    D = A | B
    E = ~ A
    plt.subplot(231);plt.imshow(A);plt.title('A')
    plt.subplot(232);plt.imshow(B,cmap='gray');plt.title('B');
    plt.subplot(233);plt.imshow(A & B,cmap='gray');plt.title('A & B');
    plt.subplot(234);plt.imshow(D,cmap='gray');plt.title('A | B');plt.axis('off');
    plt.subplot(235);plt.imshow(E,cmap='gray');plt.title('~A');plt.show();


    这里要注意plt.imshow()中cmap这个参数,它是映射意思
    如果是默认值那么1为黄色,0为紫色
    cmap=‘gray‘ 1为白色,0为黑色
    cmap=’binary‘,1为黑色,0为白色

    图像缩放

    具体原理参见博客:https://blog.csdn.net/Eastmount/article/details/82454335

    https://blog.csdn.net/Eastmount/article/details/82454335

    #encoding:utf-8
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    #解决中文显示问题
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 读取图片
    lina = cv2.imread('lina.jpg')
    cv2.imshow('lina',lina)
    print(lina.shape) #(220, 220, 3)原图是220*220的
    rows,cols,channel =lina.shape #获取原图像的行数和列数
    small_lina1 = cv2.resize(lina, (200, 100))#图像缩放
    cv2.imshow('1',small_lina1)
    small_lina2=cv2.resize(lina,None,fx=0.5,fy=0.5)#或者这么写
    cv2.imshow('2',small_lina2)
    small_lina3 = cv2.resize(lina,(int(rows*0.3),int(cols*0.3)))#或者#图像缩放 dsize(列,行)
    cv2.imshow('3',small_lina3)
    
    # #首先将要显示的多幅图片放在一个列表中,
    # #由于cv2读入的格式是BGR,(0~255),但是plt是RGB格式,所以要转换
    # #lina[:,:,[2,1,0]] 将BGR转换成RGB
    # #lina_RGB = cv2.cvtColor(lina,cv2.COLOR_BGR2RGB) #或者这样转换也可以的
    # #否则颜色很怪异
    ims=[lina[:,:,[2,1,0]],small_lina1[:,:,[2,1,0]],
    small_lina2[:,:,[2,1,0]],small_lina3[:,:,[2,1,0]]]
    titles=['原图','200*100','fx=0.5,fy=0.5','rows*0.3,cols*0.3']
    for i in range(1,5,1):
    plt.subplot(2,2,i)
    plt.imshow(ims[i-1])
    plt.title(titles[i-1],y=-0.2,fontsize=8,fontstyle= 'italic')
    plt.show()
    #注意这个要放在循环外面,否则就会出4个画布,一个figure中只有一副图片
    # 等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    以上介绍了三种缩放的方式和subplot的具体使用方法
    plt.title()中的参数,如果想把标题移动上下是y=,左右是x=,上+下-

    图像的旋转与翻转

    # encoding:utf-8
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    #解决中文显示问题
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    lina_BGR = cv2.imread('lina.jpg')
    lina = cv2.cvtColor(lina_BGR,cv2.COLOR_BGR2RGB) #将BGR转换成RGB
    rows, cols, channel = lina.shape# 原图的高、宽 以及通道数
    
    #参数:旋转中心 旋转度数 scale
    M1 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 30, 1)#参数:旋转中心 旋转度数 scale
    # 参数:原始图像 旋转参数 元素图像宽高
    lina_rotated_30 = cv2.warpAffine(lina, M1, (cols, rows))# 参数:原始图像 旋转参数 元素图像宽高
    M2 = cv2.getRotationMatrix2D((cols / 2, rows / 2), -90,1)
    lina_rotated_90 = cv2.warpAffine(lina, M2, (cols, rows))
    # # 显示图像
    # cv2.imshow("lina", lina)
    # cv2.imshow("rotated", lina_rotated)
    # # 等待显示
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()
    img1 = cv2.flip(lina, 0) #0以X轴为对称轴翻转
    img2 = cv2.flip(lina, 1) #>0以Y轴为对称轴翻转
    img3 = cv2.flip(lina, -1) #<0X轴Y轴翻转
    
    imgs = [lina,lina_rotated_30,lina_rotated_90,img1,img2,img3]
    titles = ['source','rotated 30','rotated -90',
    '以X轴为对称轴翻转','以Y轴为对称轴翻转','X轴Y轴翻转']
    
    for i in range(6):
    plt.subplot(2,3,i+1)
    plt.imshow(imgs[i])
    plt.title(titles[i],y=-0.3,fontsize=8,fontstyle= 'italic')
    plt.show()

    图像的平移

    # encoding:utf-8
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    img = cv2.imread('lina.jpg')
    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    M = np.float32([[1, 0, 0], [0, 1, 50]])#向下平移
    img1 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    print(M)
    M = np.float32([[1, 0, 0], [0, 1, -50]])#向上平移
    img2 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    M = np.float32([[1, 0, 50], [0, 1, 0]]) #向右平移
    img3 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    M = np.float32([[1, 0, -50], [0, 1, 0]]) #向左平移
    img4 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
    titles = ['向下平移', '向上平移', '向右平移', '向左平移']
    images = [img1, img2, img3, img4]
    for i in range(4):
    plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
    plt.show()

    图像的代数运算

    # encoding:utf-8
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    
    lina = cv2.imread('lina.jpg')
    lina= cv2.cvtColor(lina, cv2.COLOR_BGR2RGB)
    rows,cols,channel = lina.shape
    # A = np.ones((rows,cols,channel),dtype=int) #构造一个跟Lina大小相同的常数三维矩阵
    # A = A * 10
    # print(A.shape)
    # print(A)
    # C=lina-A
    
    wenli = cv2.imread('opencv.jpg')
    wenli = cv2.cvtColor(wenli,cv2.COLOR_BGR2RGB)
    wenli = cv2.resize(wenli,(rows,cols))
    #cv2中的add,超过255的都是255
    add1 = cv2.add(lina,wenli) #图片的大小应该相同,
    add2 = cv2.addWeighted(lina,0.8,wenli,0.2,0) #带有权重的叠加
    #add3 = cv2.add(lina,A)
    #减法
    sub1 = cv2.subtract(lina,wenli)
    #乘法
    mul1 = cv2.multiply(lina,wenli)
    #除法
    div1 = cv2. divide(lina,wenli)
    
    imgs = [lina,add1,add2,sub1,mul1,div1]
    titles = ['source','相加','权重相加','相减','相乘','相除']
    for i in range(6):
    plt.subplot(2,3,i+1)
    plt.imshow(imgs[i])
    plt.title(titles[i])
    plt.show()
    # cv2.imshow('sub1',div1)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()

    两幅图相加,韩权重的相加,相减,相乘,相除
    思考:一幅图加上一个常数

    图像的位运算+掩膜

    #把opencv图片放在Lina图的左上角 掩膜操作,位操作
    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    
    lina = cv2.imread('lina.jpg')
    lina= cv2.cvtColor(lina, cv2.COLOR_BGR2RGB)
    rows,cols,channel = lina.shape
    opcv = cv2.imread('opencv.jpg')
    opcv = cv2.resize(opcv,(int(rows / 4),int(cols / 4)))
    rows2,cols2,channel2 = opcv.shape
    
    roi = lina[0:rows2,0:cols2] #取Lina的左上角区域
    
    # Now create a mask of logo and create its inverse mask also
    opcv2gray = cv2.cvtColor(opcv,cv2.COLOR_BGR2GRAY)
    # 阈值处理函数,二值化,大于200的设置为255
    ret, mask = cv2.threshold(opcv2gray, 200, 255, cv2.THRESH_BINARY)
    mask_inv = cv2.bitwise_not(mask) #按位取反
    
    # Now black-out the area of logo in ROI
    lina_bg = cv2.bitwise_and(roi,roi,mask = mask) #按位与
    
    # Take only region of logo from logo image.
    opcv_fg = cv2.bitwise_and(opcv,opcv,mask = mask_inv)
    
    # Put logo in ROI and modify the main image
    dst = cv2.add(lina_bg,opcv_fg)
    lina[0:rows2, 0:cols2 ] = dst
    
    plt.imshow(lina)
    plt.title('lina+opencv')
    plt.show()

    简单二值化

    #简单二值化,自己规定了阈值
    import cv2
    import numpy as np
    import matplotlib.pylab  as plt
    
    img = cv2.imread('lina.jpg')
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
    ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
    ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
    ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
    ret,thresh5 = cv2.threshold(img,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()


    threshold中最后一个参数不同,表示不同的二值化方法

    大津阈值二值化

    #大津阈值二值化
    import cv2
    import numpy as np
    import matplotlib.pylab  as plt
    
    img = cv2.imread('lina.jpg',0)
    #后面加了一个0,以灰度形式加载图片,默认是1,以彩色图片形式加载
    # global thresholding 全局阈值、简单二值化
    ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
    
    # Otsu's thresholding
    ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    
    # Otsu's thresholding after Gaussian filtering
    blur = cv2.GaussianBlur(img,(5,5),0)
    ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    
    # plot all the images and their histograms
    images = [img, 0, th1,
    img, 0, th2,
    blur, 0, th3]
    titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)',
    'Original Noisy Image','Histogram',"Otsu's Thresholding",
    'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
    
    for i in range(3):
    plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
    plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)#numpy中.ravel()将数组扁平化
    plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
    plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
    plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
    
    plt.show()


    根据双峰图像的图像直方图自动计算阈值。 (对于非双峰图像,二值化不准确。)
    使用cv.threshold()但是传递了一个额外的标志v.THRESH_OTSU.对于阈值,只需传递零.然后算法找到最佳阈值并返回为第二个输出retVal。如果未使用Otsu阈值法,则retVal与之前使用的阈值相同.
    在第一种情况下,将全局阈值应用为值127.在第二种情况下,直接应用了Otsu的阈值.在第三种情况下,使用5x5高斯内核过滤图像以消除噪声,然后应用Otsu阈值处理.
    具体参考博客

    https://segmentfault.com/a/1190000015647247
    https://www.cnblogs.com/FHC1994/p/9125570.html

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐