AHK调用opencv(十五)平滑图像 – ahk_v2_beta3
二维卷积(图像滤波)
与一维信号一样,图像也可以通过各种低通滤波器(LPF)、高通滤波器(HPF)等进行过滤。LPF 有助于消除噪音、模糊图像等。HPF 滤波器有助于在图像中找到边缘。
opencv 提供了函数cv.filter2D(),用于将内核与图像卷积起来。
相关链接:https://www.cnblogs.com/lfri/p/10599420.html
卷积可视化:https://ezyang.github.io/convolution-visualizer/
从一个小小的权重矩阵,也就是卷积核(kernel)开始,让它逐步在二维输入数据上“扫描”。卷积核“滑动”的同时,计算权重矩阵和扫描所得的数据矩阵的乘积,然后把结果汇总成一个输出像素。
SetWorkingDir A_ScriptDir
hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr")
hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr")
DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl")
cv := ComObject("OpenCV.cv")
img := cv.imread("2.png")
kernel := cv.getStructuringElement(CV_MORPH_RECT:=0, ComArrayMake([1,2])) ;CV_MORPH_RECT结构元素是矩形的
dst := cv.filter2D(img,-1,kernel)
cv.imshow("Image", dst)
cv.waitKey()
cv.destroyAllWindows()
ComArrayMake(inputArray)
{
arr := ComObjArray(VT_VARIANT:=12, inputArray.Length)
Loop inputArray.Length
{
arr[A_Index-1] := inputArray[A_Index]
}
return arr
}
图像模糊(图像平滑)
图像模糊是通过将图像与低通滤波核卷积来实现的。它有助于消除噪音。它实际上从图像中删除高频内容(例如:噪声、边缘)。所以在这个操作中边缘有点模糊。OpenCV 主要提供四种模糊技术。
1.均值模糊
这是通过用一个归一化的滤波器内核与图像卷积来完成的。它只需取内核区域下所有像素的平均值并替换中心元素。这是通过函数 **cv.blur()**或 **cv.boxFilter()**完成的。
5x5 核的简单应用如下所示:
SetWorkingDir A_ScriptDir
hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr")
hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr")
DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl")
cv := ComObject("OpenCV.cv")
img := cv.imread("2.png")
blur := cv.blur(img,ComArrayMake([5,5]))
cv.imshow("Original", img)
cv.imshow("Blurred", blur)
cv.waitKey()
cv.destroyAllWindows()
ComArrayMake(inputArray)
{
arr := ComObjArray(VT_VARIANT:=12, inputArray.Length)
Loop inputArray.Length
{
arr[A_Index-1] := inputArray[A_Index]
}
return arr
}
2.高斯模糊
在这种情况下,使用高斯核代替了核滤波器。它是通过函数 **cv.GaussianBlur()**完成的。我们应该指定内核的宽度和高度,它应该是正数并且是奇数(奇数才有一个中位数)。我们还应该分别指定 x 和 y 方向的标准偏差、sigmax 和 sigmay。如果只指定 sigmax,则 sigmay 与 sigmax 相同。如果这两个值都是 0,那么它们是根据内核大小计算出来的。高斯模糊是消除图像高斯噪声的有效方法。
如果需要,可以使用函数 **cv.getGaussianKernel()**创建高斯内核。
上面函数可以替换为:
blur2 := cv.GaussianBlur(img,ComArrayMake([5,5]),0)
3.中值滤波
在这里,函数 **cv.medianBlur()**取内核区域下所有像素的中值,将中央元素替换为该中值。这对图像中的椒盐噪声非常有效。有趣的是,在上面的过滤器中,中心元素是一个新计算的值,它可能是图像中的像素值,也可能是一个新值。但在中值模糊中,中心元素总是被图像中的一些像素值所取代,可以有效降低噪音。它的内核大小应该是一个正的奇数整数。
在这个演示中,我在原始图像中添加了 50%的噪声,并应用了中间模糊。结果如下:
median := cv.medianBlur(img_cat,5)
4.双边滤波
**cv.bilateralFilter()**在保持边缘锐利的同时,对噪声去除非常有效。但与其他过滤器相比,操作速度较慢。我们已经看到高斯滤波器取像素周围的邻域并找到其高斯加权平均值。该高斯滤波器是一个空间函数,即在滤波时考虑相邻像素。但是它不考虑像素是否具有几乎相同的强度,也不考虑像素是否是边缘像素。所以它也会模糊边缘,这是我们不想做的。
双边滤波器在空间上也采用高斯滤波器,而另一个高斯滤波器则是像素差的函数。空间的高斯函数确保模糊只考虑邻近像素,而强度差的高斯函数确保模糊只考虑与中心像素强度相似的像素。所以它保留了边缘,因为边缘的像素会有很大的强度变化。
blur3 := cv.bilateralFilter(img,9,75,75)
天黑版opencv_ahk.dll使用(改变了调用方式,优化速度…)
相关文件:https://wwz.lanzouw.com/iAkK803eaaud
cv2.ahk和log.ahk来自社区群友zzZ…
可以用文件中的天黑版的v2h版ahk运行。
示例:平滑图像
#Dllload lib
#DllLoad opencv_ahk.dll
#include <cv2>
#include <log>
SetWorkingDir A_ScriptDir
;初始化opencv模块
cv := ObjFromPtr(DllCall('opencv_ahk.dll\opencv_init', 'ptr', DllCall(A_AhkPath '\ahkGetApi', 'ptr'), 'cdecl ptr'))
img := cv.imread("image/lena.png")
;二维卷积(图像滤波)
kernel := cv.getStructuringElement(cv2.CV_MORPH_RECT, [1, 2])
cv.filter2D(img, dst := cv.MAT(), -1, kernel)
cv.imshow("image", dst)
;图像模糊(图像平滑)
;均值模糊
cv.blur(img, blur := cv.MAT(), [5, 5])
cv.imshow("blur", blur)
;高斯模糊
cv.GaussianBlur(img, GaussianBlur := cv.MAT(), [5, 5], 0)
cv.imshow("GaussianBlur", GaussianBlur)
;中值滤波
img_cat := cv.imread("image/cat.jpg")
cv.medianBlur(img_cat, median := cv.MAT(), 5)
cv.imshow("median", median)
;双边滤波
cv.bilateralFilter(img, bilateralFilter := cv.MAT(), 9, 75, 75)
cv.imshow("bilateralFilter", bilateralFilter)
cv.waitKey()
cv.destroyAllWindows()
有错误请联系我改正!
本系列所有贡献者(AutoHotKey中文社区群友)不分先后:天黑请闭眼,zzZ…,演好自己,僵尸,城西,Tebayaki。