opencv从入门到放弃(二)

像素运算

  • 算数运算
    • 加、减、乘、除(两幅图像的类型、大小必须一致)
    • 引用它---调节亮度
    • 调整对比度
  • 逻辑运算
    • 或、或、非
    • 应用---遮罩层控制

代码层面的知识点

  • 常见的图像混合
  • 算法运算和集合运算

先来看一个简单的代码:

import cv2 as cv
import numpy as np

def salt(image, n):
    for k in range(n):
        # random.random随机生成一个[0,1)之间的数
        i = int(np.random.random() * image.shape[1])
        j = int(np.random.random() * image.shape[0])
        image[j, i, 0] = 255
        image[j, i, 1] = 255
        image[j, i, 2] = 255
    return image


image = cv.imread('D:/2019-02/lena.jpg')
salt = salt(image, 500)
cv.imshow('salt', salt)
cv.waitKey(0)
cv.imwrite('D:/2019-02/lena_salt.jpg', salt)

opencv从入门到放弃(二)

import cv2 as cv
import numpy as np

# 加
def add_demo(m1, m2):
     task = cv.add(m1, m2)
     return task

# 减
def sutract_demo(m1, m2):
    task = cv.subtract(m1, m2)
    return task

# 除
def div_demo(m1, m2):
    task = cv.divide(m1, m2)
    return task

# 乘
def multi_demo(m1, m2):
    task = cv.multiply(m1, m2)
    return task
    
src1 = cv.imread('D:/2019-02/lena.jpg')
src2 = cv.imread('D:/2019-02/lena2.jpg')
task = add_demo(src1, src2)
cv.imshow('image', task)
cv.imwrite('D:/2019-02/lena_add.jpg', task)
cv.waitKey(0)

除此之外,我们还可以使用以下cv中自带的函数:

image = cv.imread('D:/2019-02/.lena.jpg')
# 均值
mean_image = cv.mean(image)
# 均值和标准差
m, dev = cv.meanStdDev(image)
# 按位取与
image = cv.bitwise_and(image)
# 按位取或
image = cv.bitwise_or(image)
# 按位取非
image = cv.bitwise_not(image)

亮度和对比度

我们还可以通过cv.addWeighted()函数来修改图像的亮度和对比度

import cv2 as cv
import numpy as np


def contrast_brightenss_demo(image, c, b):
    blank = np.zeros(image.shape, image.dtype)
    # 计算两个数组的加权和(dst = c*src1 + (1-c)*src2 + b)
    # 如果c变大了,那么整个图像每个像素点的差异就会变大,例如,如果如果c变为二倍,那么原来像素之间      差异为4的差异就会增加到8;可用来调整对比度
    # 如果b增大了,那么只是整体的像素值增加了,像素之间的差异就不会变大,所以可以调整整体的亮度
    dst = cv.addWeighted(image, c, blank, 1-c, b)
    cv.imshow('contrase_bri_demo', dst)
    cv.imwrite('D:/2019-02/lena_con_bri.jpg', dst)

image = cv.imread('D:/2019-02/lena.jpg')
cv.imshow('image', image)
# 对比度设为1.5, 亮度每个通道上增加10
contrast_brightenss_demo(image, 1.5, 10)
cv.waitKey(0)

opencv从入门到放弃(二)

我们还可以使用addWeighted函数进行图像的融合

addWeighted(src1, alpha, src2, 1-alpha, 0.0 )

  • 第一个参数是输入图像1
  • 第二个参数表示图片1的融合比例
  • 第三个参数表示输入图像2
  • 第四个参数表示输入图像2的融合比例
  • 第五个参数表示偏差
sr1 = cv.imread('D:/2019-02/image16.jpg')
sr2 = cv.imread('D:2019-02/image26.jpg')
cv.namedWindow('image', cv.WINDOW_AUTOSIZE)
cv.imshow('sr1', sr1)
cv.imshow('sr2', sr2)

dst = cv.addWeighted(sr1, 0.5, sr2, 0.5, 0.0)
cv.imshow('image', dst)
cv.waitKey(0)
cv.destroyAllWindows()

ROI和泛洪填充

ROI(region of interest)也就是我们感兴趣的区域

image = cv.imread('D:/2019-02/lena.jpg')
# cv.imshow('image', image)
# cv.waitKey(0)
face = image[218:364, 215:387]
# 将lena的脸转换成灰度图
gray = cv.cvtColor(face, cv.COLOR_BGR2GRAY)
# 将灰度图转换为BGR格式,但是还是灰度图,只不过通道变为3了
bgr_face = cv.cvtColor(gray, cv.COLOR_GRAY2BGR)
# 如果直接将gray赋值过来,会报错,因为图像的通道不一样
image[218:364, 215:387] = bgr_face
cv.imshow('image', image)
cv.imwrite('D:/2019-02/lena_gray_r.jpg', image)
cv.waitKey(0)

运行结果:

opencv从入门到放弃(二)

泛洪填充

函数定义:

cv2.floodFill(img,mask,seed,newvalue(B,G,R),(loDiff1,loDiff2,loDiff3),(upDiff1,upDiff2,upDiff3),flag)

解析:

img:需要处理的图像
mask:一般设置为长宽比img大2的通道为1的数组,其中需要处理的区域设置为0,不需要处理的区域设置为1
seed:起始像素点
newvalue:需要填充的颜色
loDiff和upDiff:需要处理的与seed颜色相近的像素点,即设seed的像素为(B0,G0,R0)。若待处理的像素的值位于(B0-loDiff,G-LoDiff,B-loDiff)到(B0+upDiff,G0+upDiff,R0+upDiff)之间的话就填充newvalue
flag:一般选用cv.FLOODFILL_FIXED_RANGE,即待处理像素与seed像素比较,若不使用这个flag,则待处理像素与相邻的已填充像素比较。

import cv2 as cv
import numpy as np
 
# 泛洪填充
def fill_color_demo(image):
    copyImage = image.copy()
    h, w = image.shape[:2]
    mask = np.zeros([h+2, w+2], np.uint8)
    cv.floodFill(copyImage, mask, (30, 30), (0, 0, 0), (10, 10, 10), (20, 20, 20), cv.FLOODFILL_FIXED_RANGE)
    cv.imshow('fill_flood', copyImage)
    cv.imwrite('D:/2019-02/lena_fillflood.jpg', copyImage)
    cv.waitKey(0)
    
 
# 二值填充   
def fill_binary(image1):
    image = np.zeros(image1.shape, np.uint8)
    image[150:200,150:200] = (255, 255, 255)
    print(image[30, 30])
    cv.imshow('image', image)
    cv.imwrite('D:/2019-02/raw_pic.jpg', image)
    cv.waitKey(0)
    h, w = image.shape[:2]
    mask = np.ones([h+2, w+2], np.uint8)
    mask[100:300, 100:300] = 0
    # 在mask为0的前提下,如果像素等于0那么就进行填充
    cv.floodFill(image, mask,(100, 100), (0, 0, 255), cv.FLOODFILL_FIXED_RANGE)
    # cv.floodFill(image , mask, (100, 100), (0, 0, 255), (0, 0, 0), (125, 125, 125), cv.FLOODFILL_FIXED_RANGE)
    cv.imshow('image', image)
    cv.imwrite('D:/2019-02/pic.jpg', image)
    cv.waitKey(0)
    

    
image = cv.imread('D:/2019-02/lena.jpg')
# fill_color_demo(image)
fill_binary(image)

运行fill_color_demo函数结果:

opencv从入门到放弃(二)

运行fill_binary函数结果:

opencv从入门到放弃(二)

opencv从入门到放弃(二)

 

模糊操作

三种模糊操作的方法:

  • 均值模糊
  • 中值卷积
  • 自定义卷积

模糊操作基本原理:

  • 基于离散卷积
  • 定义好每个卷积核
  • 不同卷积核得到不同的卷积效果
  • 模糊是卷积的一种表象

均值模糊:

均值模糊对于随机噪声有很好的去噪效果

def mean_blur(image):
    # 输入一个5*5的卷积核,可以达到模糊的效果
    dst = cv.blur(image,(5, 5))
    cv.imshow('mean_blur', dst)
    cv.imwrite('D:/2019-02/image.jpg', dst)

image = cv.imread('D:/2019-02/lena.jpg')
cv.imshow('raw_image', image)
cv.imwrite('D:/2019-02/raw_lena.jpg', image)
mean_blur(image)
cv.waitKey(0)

运行结果:

原图像:

opencv从入门到放弃(二)

模糊后的:

opencv从入门到放弃(二)

中值模糊:

中值模糊对于椒盐噪声又很好的去噪效果,见下面代码:

    
def median_blur(image):
    dst = cv.medianBlur(image, 5)
    cv.imshow('median_blur', dst)
    cv.imwrite('D:/2019-02/image.jpg', dst)
    
image = cv.imread('D:/2019-02/lena_salt.jpg')
cv.imshow('raw_image', image)
cv.imwrite('D:/2019-02/raw_lena.jpg', image)
median_blur(image)
cv.waitKey(0)

运行结果,原图:

opencv从入门到放弃(二)

运行后:

opencv从入门到放弃(二)

可以看到,图像是变得更加模糊了,但是整个图像基本实现了去噪;对于椒盐噪声,中值模糊处理的更好

自定义模糊:

    
def custom_blur(image):
    kernel = np.ones([5, 5], np.float32)/25
    dst = cv.filter2D(image, -1, kernel)
    cv.imshow('custom_image', dst)
    
image = cv.imread('D:/2019-02/lena_salt.jpg')
cv.imshow('raw_image', image)
cv.imwrite('D:/2019-02/raw_lena.jpg', image)
# median_blur(image)
custom_blur(image)
cv.waitKey(0)

运行结果:

opencv从入门到放弃(二)

opencv从入门到放弃(二)

边缘保留滤波(EPF)

边缘保留滤波原理????

常用的方法:

  • 高斯双边
  • 均值迁移

直接撸代码:

高斯双边模糊

 dst = cv.bilateralFilter(src=image, d=0, sigmaColor=100, sigmaSpace=15) 

其中各参数所表达的意义:

src:原图像 

d:像素的邻域直径,可有sigmaColor和sigmaSpace计算可得,一般直接设置为0就可以了

sigmaColor:颜色空间的标准方差,一般尽可能大 

sigmaSpace:坐标空间的标准方差(像素单位),一般尽可能小

import cv2 as cv
import numpy as np

image = cv.imread('D:/2019-02/gussian.jpg')
cv.imshow('raw_image', image)
# 高斯双边模糊
dst = cv.bilateralFilter(image, 0, 125, 10)
cv.imshow('image', dst)
cv.imwrite('D:/2019-02/gussian1.jpg', dst)
cv.waitKey(0)

结果:

opencv从入门到放弃(二)

模糊后:

opencv从入门到放弃(二)

好丑。。。。。

均值迁移滤波

dst = cv.pyrMeanShiftFiltering(src=image, sp=15, sr=20)

其中各参数所表达的意义:

src:原图像

sp:空间窗的半径(The spatial window radius)

sr:色彩窗的半径(The color window radius)

import cv2 as cv
import numpy as np

image = cv.imread('D:/2019-02/gussian.jpg')
cv.imshow('raw_image', image)
# 高斯双边模糊
# dst = cv.bilateralFilter(image, 0, 125, 10)
# 均值迁移模糊
dst = cv.pyrMeanShiftFiltering(image, sp=10, sr=50)
cv.imshow('image', dst)
cv.imwrite('D:/2019-02/gussian1.jpg', dst)
cv.waitKey(0)

运行结果:

opencv从入门到放弃(二)

均值迁移会导致过度模糊

直方图

在CV中调用cv2.calcHist函数绘制直方图

cv2.calcHist(image, channels, mask, histsize, range[, hist[, accumulate]])  # 返回hist
第一个参数是输入图像
第二个参数设置直方图的通道
第三个参数是mask
第四个参数是设置直方图的个数
第五个参数表示直方图中像素值的范围
最后是两个可选参数,因为将hist返回了,所以第六个参数就没什么意义了
accumulate是一个布尔值,表示直方图是否叠加
import cv2 as cv
import matplotlib.pyplot as plt
image = cv.imread('D:/2019-02/lena.jpg')

def calcDrawHist(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()


calcDrawHist(image)
# cv.waitKey(0)

运行结果:

opencv从入门到放弃(二)

上面这幅图像是我们运行lena图像得到的三通道的像素的分布图像,可以看到是很乱的,然后我们可以选择一张颜色比较单调的一幅图像

opencv从入门到放弃(二)

使用这张图像测试,运行结果:

opencv从入门到放弃(二)

可以看到这张图像大部分都是白色的,所以整个图像的平均像素值是比较高的,从这张分布图上我们也可以看出来

直方图均衡化

通过直方图提升图像的对比度,也叫直方图均衡化

image = cv.imread('D:/2019-02/image9.jpg')
# 直方图均衡化只能对灰度图进行操作
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow('raw_image', gray)
cv.imwrite('D:/2019-02/image9-0.jpg', gray)
# 直方图均衡化
dst = cv.equalizeHist(gray)
cv.imshow('image', dst)
cv.imwrite('D:/2019-02/image99.jpg', dst)
cv.waitKey(0)

原始图像:

opencv从入门到放弃(二)

灰度图:

opencv从入门到放弃(二)

均衡化之后的图像:

opencv从入门到放弃(二)