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 cv

img = 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 np


def 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:
            break
    pass

def 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("------------------")
    pass


img = 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 np


def 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)
    pass


img = 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 * 127
    cv.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:
            break
        hsv = 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;
        pass
    pass

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

通道分离与合并

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 np


def add_demo(m1, m2):
    cv.imshow("win+linux",cv.add(m1, m2))
    cv.imshow("linux+win",cv.add(m2, m1))
    pass

def substract_demo(m1, m2):
    cv.imshow("win-linux", cv.subtract(m1, m2))
    cv.imshow("linux-win", cv.subtract(m2, m1))
    pass

def divide_demo(m1, m2):
    cv.imshow("win / linux", cv.divide(m1, m2))
    cv.imshow("linux / win", cv.divide(m2, m1))
    pass

def multiply_demo(m1, m2):
    cv.imshow("win * linux", cv.multiply(m1, m2))
    cv.imshow("linux * win", cv.multiply(m2, m1))    
    pass

win = 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:
            break
        hsv = 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))
        pass
        c = cv.waitKey(40)
        if c ==27:
            break
        pass
    pass

在这里插入图片描述

实例

  • 提升亮度对比度
def contrase_beightness_demo(image, c, b): #调整亮度对比度
    # c 代表对比度, b 代表亮度
    h, w, d = image.shape
    blank = 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)
    pass

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)
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, :] = 255
    cv.imshow("img", img)
    mask = np.ones([402, 402, 1], np.uint8 )
    mask[101:301, 101:301] = 0
    cv.floodFill(img, mask, (200, 200), (0, 0, 255), cv.FLOODFILL_MASK_ONLY)
    cv.imshow("fill img", img)
    pass

cv.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))) # 横向
    # 横向或者纵向十五个像素进行一次卷积运算
    pass

cv.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)) 
    pass

cv.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)
    pass

def blur_demo(image):
    cv.imshow("blur", cv.blur(image, (5, 5))) 
    pass


cv.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 plt


def plot_demo(image):

    pass

cv.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

在这里插入图片描述

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值