OpenCV系列 - 作者:cc 原链接:https://www.cnblogs.com/ff888/p/16783543.html
访问和修改像素值
先来理解一下,图像与一般的矩阵或张量有何不同(不考虑图像的格式,元数据等信息)。首先,一张图像有自己的属性,宽,高,通道数。其中宽和高是我们肉眼可见的属性,而通道数则是图像能呈现色彩的属性。我们都知道,光学三原色是红色,绿色和蓝色,这三种颜色的混合可以形成任意的颜色。常见的图像的像素通道也是对应的R,G,B三个通道,在OpenCV中,每个通道的取值为0~255,。(注:还有RGBA,YCrCb,HSV等其他图像通道表示)。即,一般彩色图像读进内存之后是一个h * w * c的矩阵,其中h为图像高(相当于矩阵的行),w为图像宽(相当于矩阵列),c为通道数。
比如说一张青色的图片,如图所示
青色是绿色和蓝色的混合,所以该图像的所有像素值都为R := 0; G := 255; B := 255
我们可以通过图像的行和列坐标来访问像素值,常见的RGB图像由红绿蓝三个通道组成,维度为三。
这里随意导入一张图片,名称为2.png,可以看到成功输出了图像的各方面信息。
#NoEnv ;不检查空变量是否为环境变量(建议所有新脚本使用)。 #Include opencv_ahk_lib.ahk SendMode Input 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 := ComObjCreate("OpenCV.cv") ;创建 COM 对象。 img := cv.imread("2.png") ;img := cv.imread("2.png")等于img := cv.imread("2.png", 1) 这里的1就是默认参数 ;图像宽度 矩阵的行数 rows := img.rows() ;图像高度 矩阵的列数 cols := img.cols() ;矩阵元素拥有的通道数,例如常见的彩色图像,每一个像素由RGB三部分组成,则channels = 3 channels := img.channels() ;访问中心点像素值 B := img.Vec3b_at(rows/2, cols/2)[0] G := img.Vec3b_at(rows/2, cols/2)[1] R := img.Vec3b_at(rows/2, cols/2)[2] MsgBox, 宽度:%rows%`n高度:%cols%`n颜色通道数:%channels%`nB通道颜色值:%B%`nG通道颜色值:%G%`nR通道颜色值:%R%
有了这些信息之后,下面可以根据坐标修改像素值。(方法来自Autohotkey中文社区群友zzZ…)
;修改像素值 loop, % rows{ index_rows := A_Index loop, % cols{ index_cols := A_Index img.Vec3b_set_at(index_rows - 1, index_cols - 1, ComArrayMake([255, 0, 0])) ;这里的三个参数对应B,G,R三个颜色通道 } } cv.imshow("Image", img) cv.waitKey() cv.destroyAllWindows()
这里不难看出,我们修改了B通道的值为255后,整个图片变为蓝色。
访问图像属性
图像属性包括行数,列数和通道数,图像数据类型,像素数等。
;uchar型的指针。Mat类分为了两个部分:矩阵头和指向矩阵数据部分的指针,data就是指向矩阵数据的指针。 data := img.data() ;矩阵的维度,例如5*6矩阵是二维矩阵,则dims=2,三维矩阵dims=3. dims := img.dims() ;矩阵的大小,size(cols,rows),如果矩阵的维数大于2,则是size(-1,-1) size_cols := img.size()[0] size_rows := img.size()[1] ;下面的几个属性是和Mat中元素的数据类型相关的。 type := img.type() ;表示了矩阵中元素的类型以及矩阵的通道个数,它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)。具体的有以下值: ; CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4 ; CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 ; CV_16UC1 CV_16UC2 CV_16UC3 CV_16UC4 ; CV_16SC1 CV_16SC2 CV_16SC3 CV_16SC4 ; CV_32SC1 CV_32SC2 CV_32SC3 CV_32SC4 ; CV_32FC1 CV_32FC2 CV_32FC3 CV_32FC4 ; CV_64FC1 CV_64FC2 CV_64FC3 CV_64FC4 ; 这里U(unsigned integer)表示的是无符号整数,S(signed integer)是有符号整数,F(float)是浮点数。 ; 例如:CV_16UC2,表示的是元素类型是一个16位的无符号整数,通道为2. ; C1,C2,C3,C4则表示通道是1,2,3,4 ; type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则无需使用type,使用下面的depth depth := img.depth() ; 矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值, ; 将type的预定义值去掉通道信息就是depth值: ; CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F elemSize := img.elemSize() ;矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes elemSize1 := img.elemSize1() ;矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels MsgBox, dims: %dims%`nsize_cols: %size_cols%`nsize_rows: %size_rows%`ntype: %type%`ndepth: %depth%`nelemSize: %elemSize%`nelemSize: %elemSize1%
拆分和合并图像通道
将 BGR 图像分割为单个通道,再将这些单独的通道连接到 BGR 图像。
#NoEnv #Include opencv_ahk_lib.ahk SendMode Input 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 := ComObjCreate("OpenCV.cv") new_img := ComObjCreate("OpenCV.cv.Mat") img := cv.imread("2.png") ;cv.namedWindow("Image") cv.imshow("Image", img) ;拆分图像通道 mv := ComObjCreate("OpenCV.VectorOfMat") cv.split(img, mv) cv.imshow("Image_B", mv.at(0)) cv.imshow("Image_G", mv.at(1)) cv.imshow("Image_R", mv.at(2)) ;拆分后直接合并图像通道到新矩阵 cv.merge(mv, new_img) cv.imshow("new_img", new_img) ;把B通道全部置为0,然后合并 newaddchannel := mv.at(0).clone() newaddchannel.setTo(ComArrayMake([0])) new_channels := ComObjCreate("OpenCV.VectorOfMat") new_channels.push_back(newaddchannel) new_channels.push_back(mv.at(1)) new_channels.push_back(mv.at(2)) mergedImage := ComObjCreate("OpenCV.cv.Mat") mergedImage := cv.merge(new_channels, mergedImage) cv.imshow("hebin", mergedImage) cv.waitkey() cv.destroyAllWindows()
制作图像边界
#NoEnv #Include opencv_ahk_lib.ahk SendMode Input 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 := ComObjCreate("OpenCV.cv") img := cv.imread("2.png") border_default := ComObjCreate("OpenCV.cv.Mat") border_default := cv.copyMakeBorder(img, 50, 50, 50, 50, 0, ComArrayMake([0, 0, 0])) cv.imshow("11", border_default) CV.waitkey()
可以看到,这里成功画出了厚度为50像素的框。
相关链接:https://www.cnblogs.com/wangguchangqing/p/4016179.html
dbgba优化整理OpenCV系列示例打包下载20240513:
天黑版opencv_ahk.dll使用(改变了调用方式,优化速度…)
相关文件:https://wwz.lanzouw.com/iAkK803eaaud
cv2.ahk和log.ahk来自社区群友zzZ…
可以用文件中的天黑版的v2h版ahk运行。
v2H版示例:图像的基本操作
#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')) cv.namedWindow("image") cv.moveWindow("image", 100, 100) img := cv.imread("image/test.png") ;宽,高,颜色通道数,中心点像素值 rows := img.rows cols := img.cols channels := img.channels BGR := img[rows/2, cols/2] log.info(rows, cols, channels, BGR) ; data := img.data().ptr dims := img.dims ; size := img.size type_ := img.type depth := img.depth elemSize := img.elemSize elemSize1 := img.elemSize1 log.info(dims, type_, depth, elemSize, elemSize1) ;改变中心点为白色 img[rows/2, cols/2] := [255, 255, 255] cv.imshow("image", img) ;改变所有像素点为白色 img.setTo(cv.MAT(1, 3, cv2.CV_8UC3, [255, 255, 255])) cv.imshow("image1", img) ;拆分合并图像通道 img := cv.imread("image/lena.png") vm := cv.Vector_Mat() cv.split(img, vm) cv.imshow("image_B", vm[0]) cv.imshow("image_G", vm[1]) cv.imshow("image_R", vm[2]) ;拆分后直接合并图像通道到新矩阵 new_img := cv.MAT() cv.merge(vm, new_img) cv.imshow("new_img", new_img) ;B通道像素全部改为0,然后合并 vm[0].setTo(cv.MAT(1, 1, cv2.CV_8UC3, [0, 0, 0])) cv.imshow("image_newB", vm[0]) new_img := cv.MAT() cv.merge(vm, new_img) cv.imshow("new_img1", new_img) ;制作图像边界 border_default := cv.MAT() cv.copyMakeBorder(img, border_default, 50, 50, 50, 50, cv2.CV_BORDER_CONSTANT, [0, 0, 0]) cv.imshow("new_img2", border_default) cv.waitKey() cv.destroyAllWindows()
有错误请联系我改正!
本系列所有贡献者(AutoHotKey中文社区群友)不分先后:天黑请闭眼,zzZ…,演好自己,僵尸,城西,Tebayaki。
评论(0)