OpenCV简单基础

环境搭建

https://blog.csdn.net/baidu_37366272/article/details/89292535
按照这位dalao说的装的opencv
需要自己下载安装cmake和opencv的源码

# python3.6及以上环境
# 安装扩展模块
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python #
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python #
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pytesseract #

在这里插入图片描述

import cv2 as cvimg = cv.imread('module.png', cv.IMREAD_UNCHANGED)
cv.namedWindow('img', cv.WINDOW_AUTOSIZE)
cv.imshow('img', img)
cv.waitKey(0)

测试代码

图像处理

  • 计算机中的图片:结构化存储的信息数据。
  • 图像的属性:
    • 通道数目
    • 高与宽
    • 像素数据
    • 位图深度(每个像素由多少位组成)
import cv2 as cv
import numpy as npdef get_video():capture = cv.VideoCapture(0) # 读电脑的摄像头,0代表usb摄像头while(True):ret, frame = capture.read()frame = cv.flip(frame, 1) # flip就是镜像变换,1是左右,-1上下cv.imshow("video", frame) get_image_info(frame)# frame 就是视频的每一帧c = cv.waitKey(50)if c == 27:breakpassdef get_image_info(image):print(type(image)) # image 的参数类型print(image.shape) # 图像高宽,通道数目 print(image.size) # 图像的大小 = 高*宽+通道数目print(image.dtype) # 图像的字节位数pixel_data = np.array(image) # array 获取所有的像素数据,是一个多维的矩阵print(pixel_data)print("------------------")passimg = cv.imread('module.png', cv.IMREAD_UNCHANGED)
res = cv.cvtColor(img, cv.COLOR_BGR2GRAY)# 转为灰度图像
cv.imwrite('./test.jpg', res) # 第一个参数为保存图片的位置和名字
get_video()
cv.waitKey(0)
cv.destroyAllWindows()
  • cv.VideoCapture(0) 代表读取摄像头
    • 如果没有摄像头 则 直接
cap = cv.VideoCapture()
cap.open("file")
# 同样可以播放视频
  • OpenCV读取视频并不是为了剪辑视频,那是ffmpeg的功能
  • OpenCV读取视频是为了内容分析,对象检测,对象跟踪等(读出来的视频无声音,且对视频大小有所限制)

Numpy数组操作

  • 遍历数组中的每个像素点
  • 修改数组中的像素点的值
  • data\dtype\size\shape\len 等属性

Demo1

import cv2 as cv
import numpy as npdef access_pixels(image):#访问图片的所有像素print(image.shape) # 宽,高,通道数height = image.shape[0]wight = image.shape[1]channels = image.shape[2]print("width : %s, height : %s, channels : %s"%(wight, height, channels))for row in range(height):for col in range(wight):for c in range(channels):pv = image[row, col, c]image[row, col, c] = 255-pv#让每个像素都改变然后在重新写回去# 上述三重循环实现的就是反色的效果cv.imshow("pixels_deo", image)passimg = cv.imread('module.png')
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", img)
t1 = cv.getTickCount() # cpu 转的总数
access_pixels(img)
t2 = cv.getTickCount() # cpu 转的总数
print("time : %s ms"%((t2-t1)/cv.getTickFrequency()*1000))
# cv.getTickFrequency() 获的cpu 每秒钟走多少
cv.waitKey(0)
cv.destroyAllWindows()

通过上述的代码,print time 等于 1391.912014 ms,时间还是有点长的
OpenCV有一个专门的API cv.bitwise_not(image) 用于像素取反,时间10ms以内

Demo2

# 创建3通道图片
def create_image():img = np.zeros([400, 400, 3], np.uint8)# 创建一个三位矩阵,高为400 宽为400 通道 为3通道img[:, :, 0] = np.ones([400, 400])*255 # nu.ones 使一个400*400的矩阵全为1# 这里 使用 单个 “:”冒号,代表全部区间# 第一个通道为 0, 其代表蓝色# 第二个通道为 1, 其代表绿色# 第三个通道为 2, 其代表红色cv.imshow("new image", img)# 创建单通道图片
def create_image():img = np.ones([400, 400, 1], np.uint8)img = img * 127cv.imshow("new image", img)pass

Demo3

m1 = np.array([[2, 3, 4], [5, 6, 7], [9, 10, 11]]) 
# 创建一个自己的矩阵
print(m1)
m1.fill(9)
# 将自己矩阵内数据全部赋值为9

注意:numpy.uint8作为参数类型,必须保证矩阵内参数不超过uint8能表示的范围,否则会出现精度问题

色彩空间

在这里插入图片描述

RGb色彩空间

在这里插入图片描述

HSV色彩空间
H其实可以取到360构成一个圆,但是OpenCV中只能取到180,这样就能在Uint8中存下来了
H -> 0~180 S -> 0~255 V -> 0~255

色彩空间转换API

  • 常见的色彩空间
    • RGB(多数时候使用RGB)
    • HSV(图片中物体具有特征颜色,这时将图片转为HSV就能很方便找到)
    • HIS(灰度饱和度)
    • YCrCb(早期皮肤检测用的比较多,提取人的皮肤)
    • YUV(Linux的色彩空间用的是YUV)
  • 最常见的是
    • HSV 与 RGB 的互相转换
    • YUV 与 RGB 的互相转换

OpenCV的色彩空间API

def color_space_demo(image):gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)cv.imshow("gray", gray)hsv = cv.cvtColor(image. cv.COLOR_BGR2HSV)cv.imshow("hsv", hsv)yuv = cv.cvtColor(image, cv.COLOR_BGR2YUV)cv.imshow("yuv", yuv)ycrcb = cv.cvtColor(image, cv.COLOR_BGR2YCrCb)cv.imshow("ycrcb", ycrcb)pass

inRange

在这里插入图片描述

  • 上表中为颜色在HSV中的参数,但是取值范围各不相同
  • 所以使用inRange函数直接提取对应颜色
  • 表中参数 Hmax, Hmin, Vmax, Vmin, Smax, Smin 分别代表HSV色彩空间中 HSV 的取值返回所对应的颜色
def extrace_object():cpature = cv.VideoCapture(0)while (True):ret, frame = cpature.read()if not ret:breakhsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)lower_hsv = np.array([11,43,46]) # 想要提取的颜色在表格中对应的min值范围hight_hsv = np.array([25,255,255]) # 想要提取的颜色在表格中对应的max值范围mask = cv.inRange(hsv, lower_hsv, hight_hsv) # 我这里提取的是橙色mask = cv.flip(mask, 1)cv.imshow("frame", mask)c = cv.waitKey(40)if c ==27:break;passpass

除了匹配到的颜色是白色的,其他不匹配的都是黑色

通道分离与合并

img = cv.imread('module.png')
b, g, r = cv.split(src)
cv.imshow('blue', b)
cv.imshow('green', g)
cv.imshow('red', r)src[ : , : ,2] = 0 # 给最后一个通道设为0,则就是 red 通道值没有
cv.imshow(src) # 效果是 只有 blue 和 green通道的混合
src = cv.merge([b,g,r]) # 相对于 split ,meige 是混合通道

像素级别的运算

  • 算数运算 加,减,乘,除
    • 调整亮度
    • 对比度
    • 合成图像

在这里插入图片描述

import cv2 as cv
import numpy as npdef add_demo(m1, m2):cv.imshow("win+linux",cv.add(m1, m2))cv.imshow("linux+win",cv.add(m2, m1))passdef substract_demo(m1, m2):cv.imshow("win-linux", cv.subtract(m1, m2))cv.imshow("linux-win", cv.subtract(m2, m1))passdef divide_demo(m1, m2):cv.imshow("win / linux", cv.divide(m1, m2))cv.imshow("linux / win", cv.divide(m2, m1))passdef multiply_demo(m1, m2):cv.imshow("win * linux", cv.multiply(m1, m2))cv.imshow("linux * win", cv.multiply(m2, m1))    passwin = cv.imread('./samples/data/WindowsLogo.jpg')
linux = cv.imread('./samples/data/LinuxLogo.jpg')cv.namedWindow("input window", cv.WINDOW_AUTOSIZE)
cv.imshow("windows logo", win)
cv.imshow("linux logo", linux)
add_demo(win, linux)
substract_demo(win, linux)
divide_demo(win, linux)
cv.waitKey(0)
cv.destroyAllWindows()

因为黑色是(0,0,0),所以相加并不会造成影响
百色市(255,255,255),所以不管加上多少都是知能是(255,255,255)
win+linux 和 linux+win 表达出来的图像相同
但是 win-linux 和 linux-win 减法根据传入参数有顺序变换
同理 win / linux 和 linux / win 的结果也不一样

在这里插入图片描述

每个方框的标题 与 计算对应

  • 其他计算

def others(m1, m2):print(cv.mean(m1)); # 分别查看BGR的参数值print(cv.mean(m2));M1, dev1 = cv.meanStdDev(m1)M2, dev2 = cv.meanStdDev(m2)print(dev1) # RBG的标准差差print(dev2)pass
  • 逻辑运算 与,或,非
    • 控制遮罩层
def logic_demo():cv.imshow( "m1 and m2" ,cv.bitwise_and(m1, m2)) # 与cv.imshow( "m2 and m1" ,cv.bitwise_and(m2, m1))cv.imshow( "m1 or m2" ,cv.bitwise_or(m1, m2)) # 或cv.imshow( "m2 or m1" ,cv.bitwise_or(m2, m1))cv.imshow( "m1 not m2" ,cv.bitwise_not(m1, m2)) # 非cv.imshow( "m2 not m1" ,cv.bitwise_not(m2, m1))cv.imshow( "m1 xor m2" ,cv.bitwise_xor(m1, m2)) # 异或cv.imshow( "m2 xor m1" ,cv.bitwise_xor(m2, m1))

在这里插入图片描述

  • 学习了位运算,可以发现 之前我们使用HSV的时候,捕捉到的颜色是白色,未捕捉的颜色是黑色,像极了一个遮罩。
  • 如果使用上述的遮罩 和 原图像 进行与运算,则可以显示捕捉到的原本的颜色
def logic_demo():capture = cv.VideoCapture(0)while True:res, frame = capture.read()if res == False:breakhsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)lower_hsv = np.array([11,43,46])high_hsv = np.array([25,255,255])msk = cv.inRange(hsv, lowerb=lower_hsv, upperb=high_hsv)cv.imshow("video" ,cv.bitwise_and(frame, frame, mask=msk))passc = cv.waitKey(40)if c ==27:breakpasspass

在这里插入图片描述

实例

  • 提升亮度对比度
def contrase_beightness_demo(image, c, b): #调整亮度对比度# c 代表对比度, b 代表亮度h, w, d = image.shapeblank = np.zeros([h, w, d], image.dtype) # 创意一个一样大小深度的图片cv.imshow("demo", cv.addWeighted(image, c, blank, 1-c, b)) # opencv提供的api,addWeighted是线性叠加,这里就是所有像素+b,对比度大于均值增加c,小于均值减少pass

在这里插入图片描述

ROI与泛洪填充

  • 泛洪填充:从某个点开始,递归的填充这个区域中与其相同或相近的值,直到到达边界为止

  • 上述的就是类似于Win画图中的油漆桶的效果

  • ROI区域:对于图片中该兴趣的区域,region of interest。机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域

cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./samples/data/WindowsLogo.jpg')
cv.imshow("win", win)
cv.imshow("logo", win[60:170, 100:230]) # 代表取得的区域

截取了部分区域

cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./samples/data/WindowsLogo.jpg')
linux = cv.imread('./samples/data/LinuxLogo.jpg')
cv.imshow("win", win)
logo = cv.cvtColor(win[60:170, 100:230], cv.COLOR_BGR2GRAY) # 变成灰度
backwin = cv.cvtColor(logo, cv.COLOR_GRAY2BGR) # 重新变成三通道,但还是灰色图像,因为其他两个通道已经没有了
win[60:170, 100:230] = backwin
cv.imshow("new win", win)
cv.waitKey(0)
cv.destroyAllWindows()

让变成灰色的图像重新赋值回原图,就能修改原图的这部分区域

在这里插入图片描述

def fill_color_demo(image):copyimg = image.copy()h, w = image.shape[:2]mask = np.zeros([h+2, w+2], np.uint8) # 一定要+2,保证周边像素可以被处理cv.floodFill(copyimg, mask, (60, 60), (0, 255, 255), (100,100,100), (50,50,50), cv.FLOODFILL_FIXED_RANGE)# 参数介绍,copyimg 就是传入的图像, (60,60)就是起始的判断点,(0,255,255)要改变颜色的BGR# (100,100,100) 低值  # (50,50,50) 高值# cv.FLOODFILL_FIXED_RANGE 表示上述范围内进行填充cv.imshow("fill", copyimg)passcv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./samples/data/WindowsLogo.jpg')
linux = cv.imread('./samples/data/LinuxLogo.jpg')
cv.imshow("win", win)
fill_color_demo(win)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

图像填充,填充黄色

def fill_binary():img = np.zeros([400, 400, 3], np.uint8)img[100:300, 100:300, :] = 255cv.imshow("img", img)mask = np.ones([402, 402, 1], np.uint8 )mask[101:301, 101:301] = 0cv.floodFill(img, mask, (200, 200), (0, 0, 255), cv.FLOODFILL_MASK_ONLY)cv.imshow("fill img", img)passcv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./samples/data/WindowsLogo.jpg')
linux = cv.imread('./samples/data/LinuxLogo.jpg')
fill_binary()
cv.waitKey(0)
cv.destroyAllWindows()

另一种填充模式 mask 初始化为1,填充区域初始化为0
只有mask 为0的区域才会被填充

  • folldFill(image, mask, seedPoint, newVal, rect, IoDiff, upfidd, flags)
  • img(seed.x, seed.y) - IoDiff <= img(x, y) <= img(seed.x, seed.y)+upDiff

模糊操作

  • 均值模糊
def blur_demo(image):cv.imshow("blur1", cv.blur(image, (1, 15))) # 纵向cv.imshow("blur2", cv.blur(image, (15, 1))) # 横向# 横向或者纵向十五个像素进行一次卷积运算passcv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./samples/data/WindowsLogo.jpg')
blur_demo(win)
cv.waitKey(0)
cv.destroyAllWindows()

可以处理随机的噪声图片,但是效果不能确定

  • 中值模糊
def media_demo(image):cv.imshow("origin", image)cv.imshow("blur1", cv.medianBlur(image, 5)) passcv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./jiaoyan.jpg')
media_demo(win)
cv.waitKey(0)
cv.destroyAllWindows()

专门可以用于处理椒盐噪声的图片,图片上有黑白的斑点的图片
通过中值模糊有很好的效果

在这里插入图片描述

  • 自定义模糊
def custom_blur_demo(image):kernel = np.ones([5,5], np.float32)/25 # 每次对 高为5 宽为5 对像素区域做卷积,所以要处以25,使用float是为了防止溢出dst = cv.filter2D(image, -1, kernel=kernel)# 第一个参数 输入的图像,第二个参数 ddepth几乎可以算默认,第三个参数 自定义卷积和的算法,第三个参数输出结果cv.imshow("my filter",dst)passdef blur_demo(image):cv.imshow("blur", cv.blur(image, (5, 5))) passcv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./jiaoyan.jpg')
custom_blur_demo(win)
blur_demo(win)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

不难发现 自定义模糊中(5,5)与 opencv定义的均值模糊(5,5)效果一样
也就是说我们可以通过自定义模糊程度达到不同的效果
例如:锐化等
我们可以不定义 二维,我们可以定义三维

kernel = np.array([[1,1,1], [1,1,1], [1,1,1]], np.float32)/9 #这里除以9 是因为array中的3*3=9
# 上述为 轻微模糊
kernel = np.array([[0,-1,0], [-1,5,-1], [0,-1,1]], np.float32) # 当然你也可以不除以9
# 上述为 锐化

算子kernel自定义要求:奇数,总和为1或0

边缘保留滤波(EPF)

  • 滤波 感觉类似 卷积
  • 高斯模糊仅考虑的像素空间的分布,但是如果像素差异很大,就代表这是显著特征,就不能被模糊掉
  • 一般边缘地方像素差异很大,所以其名为边缘保留滤波

在这里插入图片描述

图的解释:

  1. 第一行为原图,其图像为左白右黑的有高斯噪声的图像,标点的地方是我们进行高斯模糊计算的点
  2. 第二行为 对选定的点进行高斯模糊计算,由于左右两边的差异很大,所以原计算的区域被去掉了已不复
  3. 第三行为 边缘保留滤波之后的图形
  • 双边高斯模糊
def bi_demo(image):dst = cv.bilateralFilter(image, 0, 100, 15)cv.imshow("bi_color", dst)pass

bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType = Node)
第一个参数:原图想
第二个参数: distance,距离,一般设置为0 减少计算量 过滤时周围每个像素领域的直径
第三个参数: 颜色差异,大一点,参数越大,临近像素将会在越远的地方mix。(越大越模糊)
第四个参数: 在coordinate space中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。

在这里插入图片描述

  • 均值迁移
def bi_demo(image):dst = cv.pyrMeanShiftFiltering(image, 10, 50)cv.imshow("bi_color", dst)pass

在这里插入图片描述

有一个类似油画的效果
有的时候会对边缘有过度的处理

图像直方图(histogram)

pip install matplotlib

  • 直方图属于统计信息,卷积至于特征信息
  • 直方图均衡化,图像增强算法

在这里插入图片描述

bin 就是频距,一个小区间,16384是总的像素个数

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltdef plot_demo(image):passcv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
win = cv.imread('./timg.jpeg')
cv.imshow("origin", win)
plot_demo(win)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

def plot_demo(image):color = ('blue', 'green', 'red')for i, color in enumerate(color):hist = cv.calcHist([image], [i], None, [256], [0,256])plt.plot(hist, color=color)plt.xlim([0, 256])plt.show()pass

在这里插入图片描述

显示红绿蓝三种颜色的直方图

openCV中需要知道如何展现直方图,以及直方图的波峰波谷所代表的含义

直方图应用

直方图均衡化

opencv 的直方图均衡化都是基于 灰度图像
彩色图像需要转换为灰度图像

  • 整体直方图均衡化
    • 提升图像对比度
    • 提升图像清晰度
def eualHist_demo(image):gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)dst = cv.equalizeHist(gray)cv.imshow("qualizeHist", dst)pass
  • 局部自适应直方图均衡化
    • 创建局部自适应对象,传入图像就行了
    • 局部最好是长宽是2的幂
def clahe_demo(image):gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))dst = clahe.apply(gray)cv.imshow("clahe", dst)pass

在这里插入图片描述

从图片中的对比可以看出来,局部的均衡化比整体的均衡化更适宜
整体均衡化有的时候会出现过度的情况,这种时候就需要局部均衡化


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部