OpenCV-Python 笔记(一)GUI及核心操作

这部分笔记来源于我以前的纸质笔记本,重新写成电子文档,方便以后查阅。因为还不熟悉公式编写,后续可能不会加上公式,主要是说明和提醒自己一些需要注意的坑。

Python版本:python3.7
OpenCV版本:4.3
编译器:Pycharm

图片读取

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

# img=cv.imread("gh.jpg",1)
# # cv.namedWindow("gh",cv.WINDOW_NORMAL)
# cv.imshow("gh.jpg",img)
# k=cv.waitKey(0)
# # cv.destroyAllWindows()
# if k==27:
#     cv.destroyAllWindows()
# else:
#     cv.imwrite("gh_gray.png", img)

# img=cv.imread("gh.jpg",1)
# print(img.shape)
# img=cv.cvtColor(img,cv.COLOR_BGR2RGB)
# plt.imshow(img,cmap="gray",interpolation="bicubic")
# plt.xticks([]),plt.yticks([])
# plt.show()
plt.imshow(img,cmap="gray",interpolation="bicubic")
matplotlab 读取图片颜色空间为 **BGR**

img=cv.imread("gh.jpg",1)
cv.imshow("gh.jpg",img)
openCV读取图片颜色空间为**RGB**

matplotlab
matplotlab
openCV
在这里插入图片描述
使用openCV语句转换

img=cv.cvtColor(img,cv.COLOR_BGR2RGB)

在这里插入图片描述

改变视频框的大小和视频编码

cap=cv.VideoCapture(0)
cap.set(cv.CAP_PROP_FRAME_WIDTH,320)
cap.set(cv.CAP_PROP_FRAME_HEIGHT,240)

在显示框架时,使用适当的等待时间cv.waitKey() 。如果太小,则视频将非常快,而如果太大,则视频将变得很慢(这就是显示慢动作的方法)。正常情况下25毫秒就可以了。

保存视频

cap=cv.VideoCapture(0)
fourcc=cv.VideoWriter_fourcc(*'DIVX')
out=cv.VideoWriter("output.avi",fourcc,20.0,(640,480))

FourCC:是用于指定视频编解码器的4字节代码。可用代码它取决于平台。遵循编解码器对我来说效果很好。

在Fedora中:DIVX,XVID,MJPG,X264,WMV1,WMV2。(最好使用XVID。MJPG会生成大尺寸的视频。X264会生成非常小的尺寸的视频)
在Windows中:DIVX(尚待测试和添加)
在OSX中:MJPG(.mp4),DIVX(.avi),X264(.mkv)。

FourCC代码作为MJPG的

cv.VideoWriter_fourcc('M''J''P''G') 
cv.VideoWriter_fourcc(*'MJPG'

传递。

视频翻转

frame=cv.flip(frame,1) # 0上下翻转,1左右翻转

画图

#画布
img=np.zeros((512,512,3),np.uint8)
#线(画布,起始点,终止点,颜色,线宽)
cv.line(img,(0,0),(511,511),(255,100,0),2)
#矩形(画布,对角线起始点,对角线终止点,颜色,线宽
cv.rectangle(img,(166,166),(346,346),(0,255,0),3)
#圆形(画布,圆心,半径,颜色,线宽)线宽为-1时,填充整个圆
cv.circle(img,(256,256),90,(0,0,255),4)
#椭圆(画布,圆心,长轴和短轴长度,长轴与水平夹角,开始角度,终止角度,颜色,线宽)线宽为-1时,填充整个圆
cv.ellipse(img,(256,256),(100,50),0,0,270,255,3)

#多边形
pts=np.array([[0,0],[256,256],[512,0]],np.int32)#点集合
pts=pts.reshape(-1,1,2)#reshape点集合,(点个数,每一个点,每个点坐标)
cv.polylines(img,[pts],True,(0,255,255))#(画布,点,是否闭合,颜色)

#文字
font=cv.FONT_HERSHEY_SIMPLEX#初始化字体,SIMPLEX正常大小无衬线字体
#(画布,文本文字,文本框左下角坐标,字体,大小,颜色,字体线宽,字体比例)
cv.putText(img,"OpenCV",(170,265),font,1.5,(255,255,255),2,cv.LINE_AA)

在这里插入图片描述

画轨迹

drawing=False#开始标记
mode=False#模式选择,圆/矩形
ix,iy=-1,-1
def draw_circle(event,x,y,flags,param):
    global ix,iy,drawing,mode #坐标等全局变量
    if event==cv.EVENT_LBUTTONDOWN:#cv.EVENT_LBUTTONDOWN鼠标左键按下为True
        drawing=True#开始
        ix,iy=x,y#坐标
    elif event==cv.EVENT_MOUSEMOVE:#鼠标移动为True
        if drawing==True:
            if mode==True:
                cv.rectangle(img,(ix,iy),(x,y),(0,255,0),-1)#画矩形
            else:
                cv.circle(img,(x,y),5,(0,0,255),-1)#画圆
    elif event==cv.EVENT_LBUTTONUP:#松开鼠标左键
        drawing=False#停止
        if mode==True:
            cv.rectangle(img,(ix,iy),(x,y),(0,255,0),3)#最后一帧为矩形
        else:
            cv.circle(img,(x,y),5,(0,0,255),3)#最后为圆形

img=np.zeros((512,512,3),np.uint8)#创建画布
cv.namedWindow("image")#窗口名字
cv.setMouseCallback("image",draw_circle)#调用鼠标跟踪函数
while(1):
    cv.imshow("image",img)
    if cv.waitKey(20)&0xFF==27:
        break
cv.destroyAllWindows()

调色板&滑动条

#建立函数,因为cv.createTrackbar第五个是执行的回调函数每次跟踪栏值更改。回调函数始终具有默认参数,即轨迹栏位置。
def nothing(x):
    pass
#创建画布
img=np.zeros((300,512,3),np.uint8)
#给画布命名
cv.namedWindow("image")
#创建滑动条(滑动条名字,画布名字,默认值,最大值,回调函数)
cv.createTrackbar("R","image",0,255,nothing)
cv.createTrackbar("G","image",0,255,nothing)
cv.createTrackbar("B","image",0,255,nothing)
#开关名
switch="0:OFF\n1:ON"
#创建0/1开关
cv.createTrackbar(switch,"image",0,1,nothing)

while(1):
    cv.imshow("image",img)#显示画布
    k=cv.waitKey(1)&0xFF#等待
    if k==27:#退出开关
        break
        
    #得到四条轨迹的当前位置(滑动条的当前值)
    r=cv.getTrackbarPos("R","image")
    g = cv.getTrackbarPos("G", "image")
    b = cv.getTrackbarPos("B", "image")
    s = cv.getTrackbarPos(switch, "image")
    #如果开关是0,不改变颜色,如果是1,改变颜色
    if s==0:
        img[:]=0
    else:
        img[:]=[g,b,r]
cv.destroyAllWindows()

访问修改单个像素

px=img[100,100]

访问单个像素的颜色

blue=img[100,100,0]

由于numpy简单访问单个像素并进行修改的操作比较繁杂,所以采用item和itemset访问和修改

#访问
img.item(100,100,0)
#修改
img.itemset((100,100,0),100)

可以用img.shape来快速查看图片是不是彩色

像素总数img.size

图像数据类型img.dtype

复制,粘贴像素

#[水平像素开始:结束,垂直像素开始:结束]
k=img[100:400,200:500]
#粘贴到目标区域,如果区域大小不一致,会报错
img[600:900,700:1000]=k

获取单个通道的所有像素

b,g,r=cv.split(img)
#或者
b=img[:,:,0]
##注意:split时间复杂度比numpy操作高,如非必要,一般不使用

使通道像素归零(python的广播机制)

img[:,:,2]=0

设置边框

RED=[255,0,0]
img=cv.imread("gh.jpg")
#(图片,上边宽,下边宽,左边宽,右边宽,填充方式)
#以边界像素填充
replicate=cv.copyMakeBorder(img,100,100,100,100,cv.BORDER_REPLICATE)
#以边界为中心线镜像
reflect=cv.copyMakeBorder(img,100,100,100,100,cv.BORDER_REFLECT)
#以边界为中心线镜像,但是不包含中心线上的像素
reflect101=cv.copyMakeBorder(img,100,100,100,100,cv.BORDER_REFLECT_101)
#不好解释,大概是 fghi|abcdefghi|abcd
wrap=cv.copyMakeBorder(img,100,100,100,100,cv.BORDER_WRAP)
#用值填充
constant=cv.copyMakeBorder(img,100,100,100,100,cv.BORDER_CONSTANT,value=RED)
plt.subplot(231),plt.imshow(img,"gray"),plt.title("original")
plt.subplot(232),plt.imshow(replicate,"gray"),plt.title("replicate")
plt.subplot(233),plt.imshow(reflect,"gray"),plt.title("reflect")
plt.subplot(234),plt.imshow(reflect101,"gray"),plt.title("reflect101")
plt.subplot(235),plt.imshow(wrap,"gray"),plt.title("wrap")
plt.subplot(236),plt.imshow(constant,"gray"),plt.title("constant")
plt.show()

结果:
在这里插入图片描述

图像加法

两个图像应该具有相同的type,或者第二个图像是个标量,python会通过广播添加到每个像素。

openCV是饱和运算:超过最大值以后默认为最大值
numpy是模运算:超过最大值后取余
在这里插入图片描述
要优先使用OpenCV运算

图像融合

img1=cv.imread("gh.jpg")
img2=cv.imread("gy.jpg")
print(img1.shape)
#如果两张图片大小不一致,需要将它们转为一致
img2.resize((1080, 1920,3))
print(img2.shape)
#融合,(图片1,图片一权重,图片二,图片二权重,伽马值)
dst=cv.addWeighted(img1,0.1,img2,0.9,0)
cv.imshow("dst",dst)
cv.waitKey(0)

按位运算

img1=cv.imread("gh.jpg")
img2=cv.imread("gy.jpg")
#获取小图像长宽和通道数
rows,cols,channels=img2.shape
#开辟区域以便于粘贴
roi=img1[0:rows,0:cols]
#转换为黑白
img2gray=cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
#取掩码
ret,mask=cv.threshold(img2gray,10,255,cv.THRESH_BINARY)
#取掩码反值
mask_inv=cv.bitwise_not(mask)
#相加
img1_bg=cv.bitwise_and(roi,roi,mask=mask_inv)
img2_bg=cv.bitwise_and(img2,img2,mask=mask)
dst=cv.add(img1_bg,img2_bg)
img1[0:rows,0:cols]=dst
cv.imshow("res",img1)
cv.waitKey(0)

性能衡量和提升技术

使用cv.getTickCount()可以获得当前时间,同样用time.time也可以获取,例如:

import time
img1=cv.imread("gy.jpg")
e1=cv.getTickCount()
a=time.time()
for i in range(5,49,2):
    img1=cv.medianBlur(img1,i)
e2=cv.getTickCount()
b=time.time()
e=(e2-e1)/cv.getTickFrequency()
c=b-a
print(e,"秒",c,"秒")

结果:
在这里插入图片描述
性能优化技术

有几种技术和编码方法可以充分利用 Python 和 Numpy 的最大性能。这里只注明相关信息,并提供重要信息来源的链接。这里要注意的主要事情是,首先尝试以一种简单的方式实现算法。一旦它运行起来,分析它,找到瓶颈并优化它们。

1、尽量避免在Python中使用循环,尤其是双/三重循环等。它们本来就很慢。
2、由于Numpy和OpenCV已针对向量运算进行了优化,因此将算法/代码向量化到最大程度。
3、利用缓存一致性。
4、除非需要,否则切勿创建数组的副本。尝试改用视图。数组复制是一项昂贵的操作。

即使执行了所有这些操作后,如果你的代码仍然很慢,或者不可避免地需要使用大循环,请使用Cython等其他库来使其更快。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值