OPENCV学习笔记-第一天

OPENCV

工业应用还是Halcon https://www.mvtec.com/cn/products/halcon/documentation/

安装 numpy、opencv-python、matplotlib 并检查

import cv2 as cv  
print( cv.__version__ )  

静态图[ imread,imshow,imwrite ]

! 注意 :应当直接保存到文件运行,不要在宿主进程(如 cmd.exe)中运行

import numpy as np
import cv2 as cv
img = cv.imread('',0)
cv.imshow('frameTitle',img)
cv.waitKey(0)
cv.destroyAllWindows()
  • imread第二个参数是标志位:
    • cv.IMREAD_COLOR 1 加载彩色图像。任何图像的透明度都会被忽视。它是默认标志。
    • cv.IMREAD_GRAYSCALE 0 以灰度模式加载图像
    • cv.IMREAD_UNCHANGED -1 加载图像,包括alpha通道

视频[暂时跳过]

绘制

bg=np.zeros((512,512,8),np.uint8)
cv.line(bg,(0,0),(511,511),(255,0,0),5)
  • 线段: cv.line(图,起点,终点,BGR颜色,宽度-1表示填充否则表示宽度)
  • 矩形: cv.rectangle(图,左上角,右下角,BGR颜色,宽度)
  • 圆形: cv.circle(图,中心点,半径,BGR颜色,宽度-1表示填充否则表示宽度)
  • 椭圆: cv.ellipse(图,中心点,(长轴长,短轴长),逆时针转的角度,startAngle,endAngle,BGR颜色,宽度-1表示填充否则表示宽度)
  • 多边形: cv.polylines(图,点集,是否自动闭合,BGR颜色)
    - 点集是将 顶点坐标集合(如 [[1,2],[3,4],[5,6]])转换为ROWS12 的张量表示,一般使用reshape(-1,1,2)转换,例如
    points = np.array([[1,2],[3,4],[5,6],[7,8]],np.int32) points = points.reshape((-1,1,2)) cv.polylines(pic,[points],True,(255,255,0))
  • 文字: cv.putText(图片,文字,位置,字体,大小,颜色,厚度,线条类型)
    font = cv.FONT_HERSHEY_SIMPLEX cv.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2,cv.LINE_AA)

练习

创建拖拽出圆或矩形的绘制面板

import numpy as np
import cv2 as cv
import math

drawStatus=False
isRectangle=False
ix,iy=-1,-1
def click_callback(event,x,y,flags,param):
    global drawStatus,isRectangle,ix,iy
    if event == cv.EVENT_LBUTTONDOWN:
        drawStatus = True
        ix,iy=x,y
    elif event == cv.EVENT_MOUSEMOVE:
        if drawStatus==True:
            if isRectangle==True:
                cv.rectangle(bg,(ix,iy),(x,y),(0,255,0),1)
            else:
                cv.circle(bg,(ix,iy),math.trunc(math.fabs(x-ix)),(255,0,0),1)
    elif event == cv.EVENT_LBUTTONUP:
        drawStatus=False
        if isRectangle==True:
            cv.rectangle(bg,(ix,iy),(x,y),(0,255,0),1)
        else:
            cv.circle(bg,(ix,iy),math.trunc(math.fabs(x-ix)),(255,0,0),1)

bg = np.zeros((512,512,3),np.uint8)
cv.namedWindow('image')
cv.setMouseCallback('image',click_callback)
while(1):
    cv.imshow('image',bg)
    k = cv.waitKey(20)
    if k==77 | k==109:
        isRectangle = not isRectangle
    if cv.waitKey(20)==27:
        break
cv.destroyAllWindows()


控制栏

  • 创建控制栏 cv.createTrackbar(名称,窗体名,最小值,最大值,回调函数)
  • 获取控制栏值 cv.getTrackbarPos(名称)

def donothing(arg):
    pass

img = np.zeros((300,512,3),np.uint8)
cv.namedWindow('image')
cv.createTrackbar('B','image',0,255,donothing)
cv.createTrackbar('G','image',0,255,donothing)
cv.createTrackbar('R','image',0,255,donothing)


while(1):
    cv.imshow('image',img)
    k = cv.waitKey(20)
    if k==27:
        break
    r = cv.getTrackbarPos('R','image')
    g = cv.getTrackbarPos('G','image')
    b = cv.getTrackbarPos('B','image')
    img[:]=[b,g,r]
cv.destroyAllWindows()

章节练习

创建颜色和粗细可调的绘制面板


r,g,b,width=0,0,0,1

def donothing(val):
    pass

img = np.zeros((300,512,3),np.uint8)
cv.namedWindow('image')
cv.createTrackbar('R','image',0,255,donothing)
cv.createTrackbar('G','image',0,255,donothing)
cv.createTrackbar('B','image',0,255,donothing)
cv.createTrackbar('W','image',1,10,donothing)

ix,iy=0,0
drawStatus = False
def click_callback(event,x,y,flags,arg):
    global drawStatus,ix,iy,width
    if event == cv.EVENT_LBUTTONDOWN:
        drawStatus = True
        ix,iy=x,y
    elif event == cv.EVENT_MOUSEMOVE:
        if drawStatus is True:
            print(img)
            cv.circle(img,(ix,iy),math.trunc(math.fabs(x-ix)),(b,g,r),width)
    elif event == cv.EVENT_LBUTTONUP:
        drawStatus = False

cv.setMouseCallback('image',click_callback)
while(1):
    cv.imshow('image',img)
    k = cv.waitKey(20)
    
    if k==27:
        break
    r = cv.getTrackbarPos('R','image')
    g = cv.getTrackbarPos('G','image')
    b = cv.getTrackbarPos('B','image')
    width = cv.getTrackbarPos('W','image')
cv.destroyAllWindows()



图像的基本操作

  • 像素编辑

    • 优化前
    img = cv.imread('pic.png')
    pos = img[100,100] '''位置100,100的像素'''
    blue = img[100,100,0] ''' 访问 100,100 处的 blue 像素 ,因为是BGR颜色,第0位是蓝色 '''
    img[100,100] = [200,0,0] '''修改像素'''
    
    • 优化后
    red = img.item(5,5,2)
    img.itemset((5,5,2),100) ''' 修改 5,5 处 红色 值为 100 '''
    
  • 图像属性

    • img.shape : 行,列和通道数的元组(如果图像是彩色的) ,如果是灰度(0)则不返回元组,常用来区别是否是灰度图
    • img.size : 像素总数
    • img.dtype : 图像数据类型
  • ROI(感兴趣区域)的编辑

    • 置换
    ball = img[280:340, 330:390]
    img[273:333, 100:160] = ball
    
  • 拆分通道(耗时操作)

    • 普通做法
     b,g,r = cv.split(img) >>> img = cv.merge((b,g,r))
     or
     b = img [:, :, 0]
    
    • 索引 例如将所有红色像素都设置为0
    img [:, :, 2] = 0
    
  • 边框

    cv.copyMakeBorder(图像,上,下,左,右,边框类型)
    
  • 图像加法

    • cv.add(img1,img2) 不推荐使用numpy的 img1+img2
  • 图像融合

    • dst = cv.addWeighted(img1,0.7,img2,0.3,0)
  • 融合练习

    img1 = cv.imread('1.png')
    img2 = cv.imread('2.png')
    
    cv.namedWindow('image')
    cv.namedWindow('combine')
    bg = np.zeros((300,521,3),np.uint8)
    cv.createTrackbar('Opacity_IMG1','image',0,100,lambda x:0)
    cv.createTrackbar('Opacity_IMG2','image',0,100,lambda x:0)
    
    while(1):
        cv.imshow('image',bg)
        k = cv.waitKey(20)
        if k==27:
            break
        op1 = cv.getTrackbarPos('Opacity_IMG1','image')
        op2 = cv.getTrackbarPos('Opacity_IMG2','image')
        img3 = cv.addWeighted(img1,op1/100,img2,op2/100,0)
        cv.imshow('combine',img3)
    cv.destroyAllWindows()
    

对象追踪

  • 获取输入

    #cap = cv.VideoCapture(0) #实时视频流
    cap = cv.VideoCapture('blueBall.mp4') #视频流
    
  • 对hsv追踪时,需要先对BGR颜色转为hsv颜色,例如对于 BGR: 246,138,39 (hsv:106,215,246),使用下列参数追踪效果较好:

    121,128,72 - 253,248,255

  • 读取实时图像: _, frame = cap.read() ,其中 _ 表示是否可以继续读取,frame 表示当前一帧图像

  • 改变颜色空间 cv.cvtColor(图像/颜色, flag)

    • flag 常见的包括: COLOR_BGR2GRAY / COLOR_BGR2HSV

      可以使用 flags = [i for i in dir(cv) if i.startswith('COLOR_')] 获取所有flag

    • 当需要转换颜色时

      #例如颜色的  BGR = 10,11,12
      custom_color=np.uint8([[[10,11,12]]])
      hsv_volor=cv.cvtColor(custom_color,cv.COLOR_BGR2HSV)
      
  • 获取掩膜,可实现二值化操作

    • mask = cv.inRange(一帧hsv图像,hsv颜色左边界,hsv颜色右边界)
  • 合并图像和掩膜

    • res = cv.bitwise_and(inputFrame1,inputFrame2,outputFrame,mask=mask) ,可以使用多个掩膜合并同一个图像

当前帧(frame)、掩膜(mask)、合并结果(res) 都可以实时预览,例如使用 cv.imshow('windowName',frame) 即可

  • 扩展 : 灰度化比例公式 :R * 0.3 + G * 0.59 + B * 0.11

  • 练习1:追踪蓝色小球

    cv.namedWindow('control')
    bg = np.zeros((300,600,6),np.uint8)
    cv.createTrackbar('LB','control',0,255,lambda x:0)
    cv.createTrackbar('LG','control',0,255,lambda x:0)
    cv.createTrackbar('LR','control',0,255,lambda x:0)
    
    cv.createTrackbar('HB','control',0,255,lambda x:0)
    cv.createTrackbar('HG','control',0,255,lambda x:0)
    cv.createTrackbar('HR','control',0,255,lambda x:0)
    
    while(1):
        cap = cv.VideoCapture('mixColor.mp4') #视频流
        while(cap.isOpened()):
            _, frame = cap.read()
            if not _:
                break
            # 转换颜色空间 BGR 到 HSV
            hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
            # 定义HSV中蓝色的范围
            lb=cv.getTrackbarPos('LB','control')
            lg=cv.getTrackbarPos('LG','control')
            lr=cv.getTrackbarPos('LR','control')
            hb=cv.getTrackbarPos('HB','control')
            hg=cv.getTrackbarPos('HG','control')
            hr=cv.getTrackbarPos('HR','control')
            #print('low_bgr : %d,%d,%d'%(lb,lg,lr))
            #print('high_bgr : %d,%d,%d'%(hb,hg,hr))
            
            lower_blue = np.array([lb,lg,lr])
            upper_blue = np.array([hb,hg,hr])
    
            mask = cv.inRange(hsv, lower_blue, upper_blue)
            # 将掩膜和图像逐像素相加
            res = cv.bitwise_and(frame,frame, mask = mask)
            cv.imshow('frame',frame)
            cv.imshow('mask',mask)
            cv.imshow('res',res)
            k = cv.waitKey(5) & 0xFF
            if k == 27:
                break
        cap.release()
        print('release')
    cv.destroyAllWindows()
    
  • 练习2:追踪红、蓝、绿多颜色

    
    cv.namedWindow('control')
    bg = np.zeros((300,512,3),np.uint8)
    cv.createTrackbar('Look_B','control',0,1,lambda x:0)
    cv.createTrackbar('Look_G','control',0,1,lambda x:0)
    cv.createTrackbar('Look_R','control',0,1,lambda x:0)
    
    cv.createTrackbar('B','control',0,255,lambda x:0)
    cv.createTrackbar('G','control',0,255,lambda x:0)
    cv.createTrackbar('R','control',0,255,lambda x:0)
    cv.createTrackbar('END','control',0,255,lambda x:0)
    
    #225 - 285
    #112.5 - 142.5
    b_min=np.array([105,190,130])
    b_max=np.array([116,255,255])
    
    #0 - 75
    g_min=np.array([40,40,0])
    g_max=np.array([83,255,255])
    
    #135 - 225
    #70-115
    r_min=np.array([160,60,0])
    r_max=np.array([225,255,180])
    
    while(1):
        cap = cv.VideoCapture('allColor.mp4')
        while(cap.isOpened()):
            _,frame = cap.read()
            if not _:
                break
            k = cv.waitKey(5) & 0xff
            if k is 27:
                break
            
            o_b=cv.getTrackbarPos('Look_B','control')
            o_g=cv.getTrackbarPos('Look_G','control')
            o_r=cv.getTrackbarPos('Look_R','control')
    
            b=cv.getTrackbarPos('B','control')
            g=cv.getTrackbarPos('G','control')
            r=cv.getTrackbarPos('R','control')
            #g_min=np.array([b,g,r])
            
            maskB,maskG,maskR=0,0,0
            resB,resG,resR,res=0,0,0,frame[:]
            hsv = cv.cvtColor(frame,cv.COLOR_BGR2HSV)
            if o_b is 1:
                maskB = cv.inRange(hsv,b_min,b_max)
                resB = cv.bitwise_and(frame,frame,mask=maskB)
            if o_g is 1:
                maskG = cv.inRange(hsv,g_min,g_max)
                resG = cv.bitwise_and(frame,res,mask=maskG)
            if o_r is 1:
                maskR = cv.inRange(hsv,r_min,r_max)
                resR = cv.bitwise_and(frame,frame,mask=maskR)
    
            dst = cv.addWeighted(resB,1,resG,1,0)
            dst = cv.addWeighted(dst,1,resR,1,0)
            
            if len(dst)==4:
                cv.imshow('res',frame)
            else:
                cv.imshow('res',dst)
            #cv.imshow('maskR',maskR)
            cv.imshow('frame',frame)
        cap.release()
        print('release')
        q = cv.waitKey(100) & 0xff
        if q is 27:
            break
    cv.destroyAllWindows()
    
    

    难点: 如何通过BGR确定HSV的范围。如果没有具体数值追踪,建议保存HSV色盘,通过实际检测确定范围


几何变换 04/03/2020

  • 缩放

    • cv.resize(输入图像,(缩放后宽,缩放后高),fx=宽度缩放倍数,fy=高度缩放倍数,interpolation = 缩放模式) ,窗口一同变化

    缩放模式包括: cv.INTER_LINEAR(推荐) / cv.INTER_CUBIC(慢) / cv.INTER_AREA(默认)
    例如:cv.resize(img,fx=2,fy=0.5,interpolation=cv.INTER_LINEAR) 表示宽度放大一倍,高度缩小为原来的 1/2

  • 平移

    • cv.warpAffine(原图,移动参数,(行数rows,列数cols)) 仿射变换 warpAfine :( 是 warp-使 不是 wrap-包

          img = cv.imread('1.png',0)
          rows,cols=img.shape
          M = np.float32([[1,0,100],[0,1,50]])#转换矩阵
          res = cv.warpAffine(img,M,(rows,cols))
          cv.imshow('image',res)
      

      其中
      M[0] 表示X方向,M[0][2]表示向右平移量,M[0][1]表示逆时针斜向拉伸角度 45°,M[0][0]表示X方向缩放倍数 ;
      M[1] 表示Y方向,M[1][2]表示向下平移量,M[0][1]表示Y方向缩放倍数,M[0][0]表示顺时针斜向拉伸角度 45°;
      定义时应该考虑的是对应位置不冲突,因此:

      [[ X缩放,逆时针拉伸
      45°,X平移量 ] , [ 顺时针拉伸
      45°,Y缩放,Y平移量 ]]

    • 练习:在渲染窗口中使用鼠标控制缩放、移动图像

      
      img = cv.imread('1.png',1)
      rows,cols,x=img.shape
      cv.imshow('image',img)
      
      canMove=False
      ix,iy,res,res_move=0,0,img,img
      rrows,rcols,x=res.shape
      lenx,leny,M=0,0,np.float32([[1,0,0],[0,1,0]])#保存之前的平移量,防止回弹;或者直接用img接收warpAffine结果,但会改变原始图像
      def mouse_callback(event,x,y,flags,params):
          global canMove,ix,iy,lenx,leny,rows,cols,res,scale,img,rrows,rcols,res_move,M
          if event == cv.EVENT_LBUTTONDOWN:
              canMove=True
              ix,iy=x,y
          elif event == cv.EVENT_MOUSEMOVE:
              if canMove is True:
                  M = np.float32([[1,0,math.trunc(x-ix)+lenx],[0,1,math.trunc(y-iy)+leny]])
                  res_move = cv.warpAffine(res,M,(rrows,rcols))#img
                  cv.imshow('image',res_move)
          elif event == cv.EVENT_LBUTTONUP:
              canMove = False
              lenx+=(x-ix)
              leny+=(y-iy)
          elif event == cv.EVENT_MOUSEWHEEL:
              step = 10
              if flags>0:
                  rrows+=step
                  rcols+=step
              elif flags<0:
                  rrows-=step
                  rcols-=step
              
              res = cv.resize(img,(rrows,rcols),interpolation=cv.INTER_LINEAR)#放大后移动需返回当前窗体,否则一经置0无法恢复
              cv.imshow('image',res)
              
      cv.setMouseCallback('image',mouse_callback)
      
      
  • 旋转

    • cv.getRorationMatrix2D(中心点坐标,逆时针旋转角度,缩放倍数) 获取用于旋转的转换矩阵

      rows.cols=img.shape
      centerX,centerY=(rows-1)/2.0,(cols-1)/2.0
      M = cv.getRorationMatrix2D((centerX,centerY),90,1)#转换矩阵
      res = cv.warpAffine(img,M,(rows,cols))#最后一组参数是显示的大小,旋转后可能长宽不一,要全部显示可以适当扩大一些
      
  • 补充

    • matplotlib.pyplot 的 subplot 作用是在一个窗体绘制多幅图像
    • 定义 : matplotlib.subplot(rowsNum,colsNum,rowPlotOrder)
    • 示例:
      
      
      
      
幼稚!你要是早来几个月你就知道被 @趣往 支配的恐惧了,那时候她就是幸运闪本人_____ @拆炸弹的文青 如是说
原文地址:https://www.cnblogs.com/logicmind/p/12624499.html