美文网首页
图像处理常见方法

图像处理常见方法

作者: 邯山之郸 | 来源:发表于2020-12-01 07:54 被阅读0次

    1、颜色转换

    以红色图像为例。在图像中提取红色部分颜色。

    import cv2
    import numpy as np
    import os
    
    os.chdir(r'C:\Users\Eddie\Desktop')
    
    img = cv2.imread('test111.jpg')
    #各种滤波
    blur = cv2.blur(img,(5,5))
    blur0 = cv2.medianBlur(blur,5)
    blur1 = cv2.GaussianBlur(blur0,(5,5),0)
    blur2 = cv2.bilateralFilter(blur1,9,75,75)
    # 颜色转换,RGB->HSV
    hsv = cv2.cvtColor(blur2,cv2.COLOR_BGR2HSV)
    # 在HSV空间的颜色范围,参考下表中的颜色区间
    lower_red = np.array([156,20,70])
    upper_red = np.array([180,255,255])
    mask = cv2.inRange(hsv,lower_red,upper_red)
    
    # 与原图与操作,只剩下希望留下的颜色
    res = cv2.bitwise_and(img,img,mask = mask)
    
    
    cv2.imshow('blur',res)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    image.png
    image.png

    2. 二值化处理

    1) 二值化处理

    # 手动二值化处理
    # 设置阈值大小 threshold
    thresh = 125
    # 设置超过阈值像素值的最大值
    maxval = 255
    # THRESH_BINARY:超过阈值为maxval,否则为0
    # THRESH_BINARY_INV:超过阈值为0,否则为maxval(相当于上个参数取反)
    # THRESH_TRUNC:超过阈值为thresh,低于阈值灰度值不变
    # THRESH_TOZERO:超过阈值灰度值不变,否则为0
    # THRESH_TOZERO_INV:超过阈值为0,低于阈值灰度值不变
    ret, thresh1 = cv2.threshold(img, thresh, maxval, cv2.THRESH_BINARY)
    ret, thresh2 = cv2.threshold(img, thresh, maxval, cv2.THRESH_BINARY_INV)
    ret, thresh3 = cv2.threshold(img, thresh, maxval, cv2.THRESH_TRUNC)
    ret, thresh4 = cv2.threshold(img, thresh, maxval, cv2.THRESH_TOZERO)
    ret, thresh5 = cv2.threshold(img, thresh, maxval, 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()
    
    

    2) 自动二值化处理

    img2 = cv2.imread('002.tif', 0)
    # rows, cols = img2.shape
    # Otsu阈值
    ret1, thresh1 = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
    # Otsu可与其他二值化方式一起使用
    ret2, thresh2 = cv2.threshold(blur, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
    # # Triangle阈值-很少用到
    # ret3, thresh3 = cv2.threshold(img2, 0, 255, cv2.THRESH_TRIANGLE)
    # ret4, thresh4 = cv2.threshold(blur, 0, 255, cv2.THRESH_TRIANGLE)
    
    titles = ['original image', "Otsu's", "Otsu's+Binary"] # "Triangle", "Triangle-Otsu's"
    images = [img, thresh1, thresh2] # thresh3, thresh4
    
    for i in range(3):
        plt.subplot(1, 3, i+1)
        plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([])
        plt.yticks([])
    
    plt.show()
    

    3) 自适应二值化

    # maxval为像素值的最大值默认设为255
    # blockSize为计算像素阈值的像素邻域的大小:3、5、7。。。。、99
    # C为从平均值或加权平均值中减去常数,一般设置为0-50
    blockSize = 25
    C = 5
    # 高斯BINARY
    thresh1 = cv2.adaptiveThreshold(img2, maxval, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blockSize, C)
    # 高斯BINARY_INV
    thresh2 = cv2.adaptiveThreshold(img2, maxval, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, blockSize, C)
    # 平均BINARY
    thresh3 = cv2.adaptiveThreshold(img2, maxval, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize, C)
    # 平均BINARY_INV
    thresh4 = cv2.adaptiveThreshold(img2, maxval, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, blockSize, C)
    
    titles = ['original image', "gaussian binary", "gaussian binary_inv", "mean binary", "mean binary_inv"]
    images = [img2, thresh1, thresh2, thresh3, thresh4]
    
    for i in range(5):
        plt.subplot(2, 3, i+1)
        plt.imshow(images[i], 'gray')
        plt.title(titles[i])
        plt.xticks([])
        plt.yticks([])
    
    plt.show()
    

    3. 掩码处理

    如果摄像头固定,而监控目标位置也相对固定,则可以利用掩码预处理图像,使得计算机只处理某个区域的图像。

    mask = np.zeros(np.shape(img),dtype=np.uint8)
    mask[200:770,190:260]=255 # 原点在左上角,x向下,y向右
    img= cv2.add(img,np.zeros(np.shape(img),dtype=np.uint8),mask=mask)
    cv2.imshow('mask',img)
    cv2.waitKey(0)
    

    4. 直线检测之霍夫变换

    前提:边缘检测完成。

    cv2.HoughLines()
        dst:   输出图像. 它应该是个灰度图 (但事实上是个二值化图)
        lines: 储存着检测到的直线的参数对 (r,\theta) 的容器 
        rho : 参数极径 r 以像素值为单位的分辨率. 我们使用 1 像素.
        theta: 参数极角 \theta 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
        threshold:    设置阈值: 一条直线所需最少的的曲线交点
        srn and stn:  参数默认为0
    
    cv2.HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 )
        dst:    输出图像. 它应该是个灰度图 (但事实上是个二值化图) 
        lines:  储存着检测到的直线的参数对 (x_{start}, y_{start}, x_{end}, y_{end}) 的容器
        rho :   参数极径 r 以像素值为单位的分辨率. 我们使用 1 像素.
        theta:  参数极角 \theta 以弧度为单位的分辨率. 我们使用 1度 (即CV_PI/180)
        threshold:    设置阈值: 一条直线所需最少的的曲线交点。超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。
        minLinLength: 能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃.
        maxLineGap:   能被认为在一条直线上的两点的最大距离。
    

    5. 边缘检测

    Canny

    edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]]) 
    

    必要参数:

    • 第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;
    • 第二个参数是阈值1;
    • 第三个参数是阈值2。
      Canny检测只能针对灰度图,使用代码如下:
    import cv2
    import numpy as np  
     
    img = cv2.imread("D:/image_gray.jpg", 0)
     
    img = cv2.GaussianBlur(img,(3,3),0)
    canny = cv2.Canny(img, 50, 150)
     
    cv2.imshow('Canny', canny)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    在github上有一个可以在运行时调整阈值大小的程序。其代码如下:

    import cv2
    import numpy as np
     
    def CannyThreshold(lowThreshold):
        detected_edges = cv2.GaussianBlur(gray,(3,3),0)
        detected_edges = cv2.Canny(detected_edges,lowThreshold,lowThreshold*ratio,apertureSize = kernel_size)
        dst = cv2.bitwise_and(img,img,mask = detected_edges)  # just add some colours to edges from original image.
        cv2.imshow('canny demo',dst)
     
    lowThreshold = 0
    max_lowThreshold = 100
    ratio = 3
    kernel_size = 3
     
    img = cv2.imread('D:/lion.jpg')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
     
    cv2.namedWindow('canny demo')
     
    cv2.createTrackbar('Min threshold','canny demo',lowThreshold, max_lowThreshold, CannyThreshold)
     
    CannyThreshold(0)  # initialization
    if cv2.waitKey(0) == 27:
        cv2.destroyAllWindows()
    

    6. 直线检测(FLD)

    Fast Line Detector: opencv-contrib-python模块才行,不是opencv-python模块。

    def FLD(image):
        # Create default Fast Line Detector class
        fld = cv2.ximgproc.createFastLineDetector()
        # Get line vectors from the image
        lines = fld.detect(image)
        # Draw lines on the image
        line_on_image = fld.drawSegments(image, lines)
        # Plot
        plt.imshow(line_on_image, interpolation='nearest', aspect='auto')
        plt.show()
        return line_on_image
    

    其中 lines = fld.detect(image)返回的是各个线段的顶点坐标。四个一组。很多直线被分成了很多线段,需要重新整合一下才好。

    cv2.ximgproc.createFastLineDetector()可以带参数,参与意义如下:

    retval = cv.ximgproc.createFastLineDetector( [, _length_threshold[, _distance_threshold[, _canny_th1[, _canny_th2[, _canny_aperture_size[, _do_merge]]]]]] ) 
     
    Parameters 
    _length_threshold 10 - Segment shorter than this will be discarded 
     
    _distance_threshold 1.41421356 - A point placed from a hypothesis line segment farther than this will be regarded as an outlier 
     
    _canny_th1 50 - First threshold for hysteresis procedure in Canny() 
     
    _canny_th2 50 - Second threshold for hysteresis procedure in Canny() 
     
    _canny_aperture_size 3 - Aperturesize for the sobel operator in Canny() 
     
    _do_merge false - If true, incremental merging of segments will be perfomred
    

    功能:找出检测结果中最长的一根直线,绘制该直线及其两个端点,并且在该直线一个端点处绘制箭头。

    import cv2
    import numpy as np
    from scipy.spatial import distance as dist
     
    img = cv2.imread('sDQLM.png')
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
     
    #Create default Fast Line Detector (FSD)
    fld = cv2.ximgproc.createFastLineDetector()
     
    #Detect lines in the image
    lines = fld.detect(gray)
     
    dMax = 0
    bx_Max = 0
    by_Max = 0
    ex_Max = 0
    ey_Max = 0
     
    for L in lines:
     
        bx,by,ex,ey = L[0]
        
        # compute the Euclidean distance between the two points,
        D = dist.euclidean((bx, by), (ex, ey))
        
        if D > dMax:
            dMax = D
            bx_Max = bx
            by_Max = by
            ex_Max = ex
            ey_Max = ey
            
    lineMax = np.array([[[bx_Max, by_Max, ex_Max,ey_Max]]])
    #Draw detected lines in the image
    drawn_img = fld.drawSegments(gray,lineMax,True)
    cv2.circle(drawn_img, (bx_Max, by_Max), 1, (255,0,0), 2)#line begin
    cv2.circle(drawn_img, (ex_Max, ey_Max), 1, (0,255,0), 2)#line end
     
    cv2.imshow("FLD", drawn_img)
    cv2.waitKey(0)
    

    7. 录像

    import cv2
    import numpy as np
    import time, datetime
    import sys
    def camera_record(fnamesave):
    
           """
           函数名:cv2.VideoCapture()
           功  能:通过摄像头捕获实时图像数据
           返回值:有
           参数一:摄像头代号,0为默认摄像头,笔记本内建摄像头一般为 0
                  或者填写视频名称直接加载本地视频文件
           """
           url = "rtsp://admin:zxcvbnm123@192.168.121.8/Streaming/Channels/2" # 可以使用通道1或者2
           cap = cv2.VideoCapture(url)  # 创建一个 VideoCapture 对象,打开摄像头
           time_begin = time.time()
           """
           函数名:cap.set( propId , value )
           功  能:设置视频参数。设置视频的宽高值和摄像头有关
                  使用笔记本内置摄像头时只能设置为 1280*720 以及 640*480,哪怕设置值不同时都会自动校正过来,并且仍然返回 True
           返回值:布尔值
           参数一:需要设置的视频参数
           参数二:设置的参数值
           """
           # cap.set(3, 480)
           # cap.set(4, 320)
    
           flag = 1;  # 设置一个标志,用来输出视频信息
           """
           函数名:cv2.isOpened()
           功  能:返回一个布尔值( True / False ),检查是否初始化成功,成功返回 True
           返回值:布尔值
           """
    
           # fourcc = cv2.VideoWriter_fourcc(*'XVID')#视频存储的格式
           # fourcc = cv2.VideoWriter_fourcc(*'MJPG')
           fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
           fps = cap.get(cv2.CAP_PROP_FPS)  # 帧率
           # 视频的宽高
           size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), \
                  int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
           
           # print(fnamesave)
           out = cv2.VideoWriter(fnamesave, fourcc, fps, size)  # 视频存储       
    
           while (out.isOpened()):  # 循环读取每一帧
                  """
                  函数名:cap.read()
                  功  能:返回两个值
                         先返回一个布尔值,如果视频读取正确,则为 True,如果错误,则为 False,也可用来判断是否到视频末尾
                         再返回一个值,为每一帧的图像,该值是一个三维矩阵
                         通用接收方法为:
                         ret,frame = cap.read();
                         这样 ret 存储布尔值,frame 存储图像
                         若使用一个变量来接收两个值,如
                         frame = cap.read()
                         则 frame 为一个元组,原来使用 frame 处需更改为 frame[1]
                  返回值:R1:布尔值
                         R2:图像的三维矩阵
                  """
                  if time.time()-time_begin > 3600:  # 3600秒,即一个小时
                         return 0
                  ret_flag, Vshow = cap.read()
                  # gray = cv2.cvtColor(Vshow,cv2.COLOR_BGR2GRAY)
                  # cv2.imshow("Gray",gray)
                  if ret_flag is False:  # ret为false则关闭
                         exit()
    
                  cv2.namedWindow('video', cv2.WINDOW_AUTOSIZE)  # 创建一个名为video的窗口
                  cv2.imshow("video", Vshow)  # 窗口显示,显示名为 Capture_Test
                  out.write(Vshow)  # 将捕捉到的图像存储
    
                  k = cv2.waitKey(1) & 0xFF  # 每帧数据延时 1ms,延时不能为 0,否则读取的结果会是静态帧
                  if k == ord('s'):  # 若检测到按键 ‘s’,打印字符串
                         """
                         函数名:cap.get( propId )
                         功  能:查询视频的参数
                         返回值:无
                         参数一:查询的视频参数,其中部分值可以使用 cap.set() 进行修改
                         """
                         print(cap.get(3))
                         print(cap.get(4))
    
                  elif k == ord('q'):  # 若检测到按键 ‘q’,退出
                         sys.exit(0)
                         break
    
           cap.release()  # 释放摄像头
           out.release()
           cv2.destroyAllWindows()  # 删除建立的全部窗口
    
    if __name__ == "__main__":
        while True:
           fname=datetime.datetime.now().strftime('outvideo%Y-%m-%d-%H') # 一个小时换一次文件名
           fdir = r'D:/'
           fnamesave = fdir+fname+r'.mp4'
           camera_record(fnamesave)
           
    
    

    8. 摄像头设置cap.set()

    import cv2
     
    #选择摄像头号,一般从 0 开始
    cap = cv2.VideoCapture(0)
     
    #先设置参数,然后读取参数
    for i in range(47):
        print("No.={} parameter={}".format(i,cap.get(i)))
     
    while True:
        ret, img = cap.read()
        cv2.imshow("input", img)
    # 按 ESC 键退出
        key = cv2.waitKey(10)
        if key == 27:
            break
     
    cv2.destroyAllWindows() 
    cv2.VideoCapture(0).release()
    

    运行结果可以看到,那些不是-1的,就是可以设置。关于序号的说明如下:

    0. CV_CAP_PROP_POS_MSEC Current position of the video file in milliseconds.
    1. CV_CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next.
    2. CV_CAP_PROP_POS_AVI_RATIO Relative position of the video file
    3. CV_CAP_PROP_FRAME_WIDTH Width of the frames in the video stream.
    4. CV_CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream.
    5. CV_CAP_PROP_FPS Frame rate.
    6. CV_CAP_PROP_FOURCC 4-character code of codec.
    7. CV_CAP_PROP_FRAME_COUNT Number of frames in the video file.
    8. CV_CAP_PROP_FORMAT Format of the Mat objects returned by retrieve() .
    9. CV_CAP_PROP_MODE Backend-specific value indicating the current capture mode.
    10. CV_CAP_PROP_BRIGHTNESS Brightness of the image (only for cameras).
    11. CV_CAP_PROP_CONTRAST Contrast of the image (only for cameras).
    12. CV_CAP_PROP_SATURATION Saturation of the image (only for cameras).
    13. CV_CAP_PROP_HUE Hue of the image (only for cameras).
    14. CV_CAP_PROP_GAIN Gain of the image (only for cameras).
    15. CV_CAP_PROP_EXPOSURE Exposure (only for cameras).
    16. CV_CAP_PROP_CONVERT_RGB Boolean flags indicating whether images should be converted to RGB.
    17. CV_CAP_PROP_WHITE_BALANCE Currently unsupported
    18. CV_CAP_PROP_RECTIFICATION Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently)
    

    9. 三维显示灰度图

    Y = np.arange(0, np.shape(img_gray)[0], 1)
    X = np.arange(0, np.shape(img_gray)[1], 1)
    X, Y = np.meshgrid(X, Y)
    fig = plt.figure()
    ax = plt.axes(projection="3d")
    ax.plot_surface(X, Y, img_gray, cmap='hot') #'gist_rainbow')  #  cmap='hot'
    plt.show()
    

    说明:输入灰度图(img_gray),X, Y是图像矩阵的两个维度。灰度值是第三维。可以看到灰度和人眼感知之间的关系。

    相关文章

      网友评论

          本文标题:图像处理常见方法

          本文链接:https://www.haomeiwen.com/subject/bgrdwktx.html