1 图像融合
被叠加的两张图片的大小、类型(高度/宽度/通道数)必须相同。 但是如果这两张图片大小不相同,有什么方法解决?具体解决方法请点击此处查看
1.1 cv2.add(img1,img2)
:直接对两张图片作加法运算
Numpy中可以直接用res = img1 + img2相加,但这两者的结果并不相同,因为OpenCV中的加法运算是饱和运算(就是当运算结果大于一个上限或小于一个下限时,结果就等于上限或是下限。),而Numpy中的加法运算是取模运算。
如下面代码中cv2.add(x,y)运行结果为[[255]],是因为250+10 = 260 >= 255,所以结果就等于上限255,x+y运行结果为[4],是因为250+10 = 260 mod 255 = 4。
from imutils import *
import os
os.chdir('D:/BaiduYunDownload/')
img1 = imread('image1.jpg')
img2 = imread('image2.jpg')
show(img1)
show(img2)
x = np.uint8([250])
y = np.uint8([10])
print(cv2.add(x,y)) #运行结果为[[255]]
print(x+y) #运行结果为[4]
res = img1 + img2
show(res)#显示使用数组加法后的图片
add = cv2.add(img1,img2)
show(add)#显示使用OpenCV中add函数的图片
想了解上面代码中的from imutils import *
点击此处
1.2 cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
:也是一种图片相加的操作,可以实现两张图片的线性融合。
将沙漠和老虎的图片融合,沙漠的权重为0.6,老虎的权重为0.4
from imutils import *
import os
os.chdir('C:/Users/lenovo/Pictures/')
img1 = imread('desert.jpg')
img2 = imread('tiger.jpg')
dst = cv2.addWeighted(img1,0.6,img2,0.4,0)#γ的取值为0
show(dst)
运行结果为:
如果想不断调节alpha的值,查看不同情况下的融合图像。(可以增加一个滑动条)
import cv2
import numpy as np
import os
os.chdir('C:/Users/lenovo/Pictures/')
img1 = cv2.imread('desert.jpg')
img2 = cv2.imread('tiger.jpg')
cv2.namedWindow('addImage')
#回调函数
def nothing(x):
pass
#添加一个调节alpha值得滑动条
alpha = 0 #初始化
cv2.createTrackbar('alpha','addImage',0,10,nothing)
while(1):
cv2.imshow('addImage',dst)
k = cv2.waitKey(1) & 0xFF
if k == ord('q'): #按q键退出
break
#获得滑动条的value值
alpha = cv2.getTrackbarPos('alpha','addImage')
alpha = alpha/10
beta = 1.0 - alpha
dst = cv2.addWeighted(img1,alpha,img2,beta,0)#γ的取值为0
cv2.destroyAllWindows()
2 图像的边缘检测
2.1 OpenCV-Python 中 Canny() 参数
步骤:
- 彩色图像转换为灰度图像(以灰度图或者单通道图读入)
- 对图像进行高斯模糊(去噪)
- 计算图像梯度,根据梯度计算图像边缘幅值与角度
- 沿梯度方向进行非极大值抑制(边缘细化)
- 双阈值边缘连接处理
- 二值化图像输出结果
-
""" cv2.Canny(image, # 输入原图(必须为单通道图) threshold1, threshold2, # 较大的阈值2用于检测图像中明显的边缘 [, edges[, apertureSize[, # apertureSize:Sobel算子的大小 L2gradient ]]]) # 参数(布尔值): true: 使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放), false:使用L1范数(直接将两个方向导数的绝对值相加)。 """ import cv2 import numpy as np original_img = cv2.imread("qingwen.png", 0) # canny(): 边缘检测 img1 = cv2.GaussianBlur(original_img,(3,3),0) canny = cv2.Canny(img1, 50, 150) # 形态学:边缘检测 _,Thr_img = cv2.threshold(original_img,210,255,cv2.THRESH_BINARY)#设定红色通道阈值210(阈值影响梯度运算效果) kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) #定义矩形结构元素 gradient = cv2.morphologyEx(Thr_img, cv2.MORPH_GRADIENT, kernel) #梯度 cv2.imshow("original_img", original_img) cv2.imshow("gradient", gradient) cv2.imshow('Canny', canny) cv2.waitKey(0) cv2.destroyAllWindows()
2.2 利用sobel算子进行源码的边缘检测
索贝尔算子(Sobel operator)主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。
Sobel卷积因子为:
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:
具体计算如下:
其中f(a,b), 表示图像(a,b)点的灰度值;图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
通常,为了提高效率,使用不开平方的近似值:
如果梯度G大于某一阀值 则认为该点(x,y)为边缘点,然后可用以下公式计算梯度方向:
Sobel算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法。
实现的代码如下:
import cv2
import numpy as np
import math
img = cv2.imread('1.jpg', 1)
info = img.shape
cv2.imshow('src', img)
height = info[0]
width = info[1]
# sobel 1.算子模板 2.图片卷积 3.阈值判决
# 2.[1 2 3 4][a b c d] a*1+b*2+c*3+d*4 = dst
# sqrt(a*a+b*b) = f>th
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = np.zeros((height, width, 1), np.uint8)
for i in range(0, height-2):
for j in range(0, width-2):
gy = gray[i, j]*1 + gray[i, j+1]*2 + gray[i, j+2]*1 - gray[i+2, j]*1 - gray[i+2, j+1]*2 - gray[i+2, j+2]*1
gx = gray[i, j] + gray[i+1, j]*2 + gray[i+2, j] - gray[i, j+2] - gray[i+1, j+2]*2 - gray[i+2, j+2]*1
grad = math.sqrt(gx*gx+gy*gy)
if grad > 50:
dst[i, j] = 255
else:
dst[i, j] = 0
cv2.imshow('dst', dst)
cv2.waitKey(0)
最后的实验效果是: