morphologyex 参数
- 格式:docx
- 大小:14.99 KB
- 文档页数:2
基于Opencv实现颜⾊识别彩⾊模型数字图像处理中常⽤的采⽤模型是RGB(红,绿,蓝)模型和HSV(⾊调,饱和度,亮度),RGB⼴泛应⽤于彩⾊监视器和彩⾊视频摄像机,我们平时的图⽚⼀般都是RGB模型。
⽽HSV模型更符合⼈描述和解释颜⾊的⽅式,HSV的彩⾊描述对⼈来说是⾃然且⾮常直观的。
HSV模型HSV模型中颜⾊的参数分别是:⾊调(H:hue),饱和度(S:saturation),亮度(V:value)。
由A. R. Smith在1978年创建的⼀种颜⾊空间, 也称六⾓锥体模型(Hexcone Model)。
(1)⾊调(H:hue):⽤⾓度度量,取值范围为0°~360°,从红⾊开始按逆时针⽅向计算,红⾊为0°,绿⾊为120°,蓝⾊为240°。
它们的补⾊是:黄⾊为60°,青⾊为180°,品红为300°;(2)饱和度(S:saturation):取值范围为0.0~1.0,值越⼤,颜⾊越饱和。
(3)亮度(V:value):取值范围为0(⿊⾊)~255(⽩⾊)RGB转成HSV设 (r, g, b) 分别是⼀个颜⾊的红、绿和蓝坐标,它们的值是在 0 到 1 之间的实数。
设 max 等价于 r, g 和 b 中的最⼤者。
设 min 等于这些值中的最⼩者。
要找到在 HSV 空间中的 (h, s, v) 值,这⾥的 h ∈ [0, 360)是⾓度的⾊相⾓,⽽ s, v ∈ [0,1] 是饱和度和亮度,⽅法如下:max=max(R,G,B)min=min(R,G,B)if R = max, H = (G-B)/(max-min)if G = max, H = 2 + (B-R)/(max-min)if B = max, H = 4 + (R-G)/(max-min)H = H * 60if H < 0, H = H + 360V=max(R,G,B)S=(max-min)/maxOpenCV下有个函数可以直接将RGB模型转换为HSV模型,OpenCV中H∈ [0, 180), S ∈ [0, 255], V ∈ [0, 255]。
opencv——morphologyEx开运算、闭运算、形态学梯度、顶帽、⿊帽开运算:先腐蚀后膨胀。
能够排除⼩亮点。
闭运算:先膨胀后腐蚀。
能够排除⼩⿊点。
形态学梯度:膨胀图 — 腐蚀图。
对⼆值图像进⾏这⼀操作,可将图块的边缘突出出来,故可⽤来保留物体边缘轮廓。
顶帽:原图 — 开运算结果。
可以认为是找到那些被开运算排除的⼩亮点。
⿊帽:闭运算结果 — 原图。
可以认为是找到那些被闭运算排除的⼩⿊点。
为了⽅便,opencv 将这些操作集合到了⼀个函数中 morphologyEx。
要实现不同操作,仅需改变其第三个成员变量形态学运算标识符。
形态学滤波:morphologyEx 函数void morphologyEx(InputArray src, OutputArray dst, int op, InputArray kernel, Point anchor = Point(-1, -1), intiterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue =morphologyDefaultBorderValue());src,输⼊图像,即原图像,填 Mat 类的对象即可。
dst,⽬标图像,需要和原图⽚有⼀样的尺⼨和类型。
op,形态学运算的类型。
MORPH_ERODE = 0, //腐蚀MORPH_DILATE = 1, //膨胀MORPH_OPEN = 2, //开操作MORPH_CLOSE = 3, //闭操作MORPH_GRADIENT = 4, //梯度操作MORPH_TOPHAT = 5, //顶帽操作MORPH_BLACKHAT = 6, //⿊帽操作kernel,膨胀操作的核。
当为 NULL 时,表⽰的是使⽤参考点位于中⼼,⼤⼩ 3×3 的核。
⼀般⽤函数 getStructuringElement 配合这个参数使⽤。
指静脉识别代码指静脉识别是一种生物特征识别技术,它通过识别人体手指的静脉纹理来实现身份认证和授权。
相比于传统的密码、卡片等身份认证方式,指静脉识别具有更高的准确性、更强的安全性和更便捷的使用体验。
在金融、医疗、政务等领域得到了广泛应用。
1. 指静脉识别原理指静脉识别是基于人体生物特征进行身份认证和授权的技术。
每个人手指上的静脉纹理都是独一无二的,就像人类的DNA一样。
当手指放置在读取器上时,读取器会发射近红外光线,并通过摄像头捕捉图像。
然后,计算机会对图像进行处理和分析,提取出图像中的指静脉信息,并与预先存储在数据库中的用户信息进行比对,从而完成身份认证或授权。
2. 指静脉识别技术优势2.1 高准确性由于每个人手指上的静脉纹理都是独一无二的,因此指静脉识别技术具有非常高的准确性。
根据相关研究,指静脉识别的错误率只有万分之一左右,远远低于其他生物特征识别技术。
2.2 高安全性指静脉识别技术具有非常高的安全性。
由于指静脉信息是内部生物特征,不易被模拟或复制。
此外,指静脉识别技术还可以检测出假体、假手指等欺骗行为,进一步提高了系统的安全性。
2.3 便捷易用相比于传统的密码、卡片等身份认证方式,指静脉识别具有更便捷、更易用的特点。
用户只需要将手指放置在读取器上即可完成身份认证或授权,无需记忆复杂的密码或携带卡片等物品。
3. 指静脉识别应用场景3.1 金融领域在金融领域,指静脉识别技术被广泛应用于ATM机、移动支付等场景中。
通过使用指静脉识别技术进行身份认证和授权,可以有效防止银行卡被盗刷、密码被破解等安全问题。
3.2 医疗领域在医疗领域,指静脉识别技术被应用于电子病历管理、药品配送等场景中。
通过使用指静脉识别技术,可以确保医疗信息的安全性和准确性,同时也可以提高医院工作效率。
3.3 政务领域在政务领域,指静脉识别技术被应用于身份证明、公共服务等场景中。
通过使用指静脉识别技术进行身份认证和授权,可以有效防止虚假身份证明和欺诈行为。
C++中实现OpenCV图像分割与分⽔岭算法分⽔岭算法是⼀种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从⽽将在空间位置上相近并且灰度值相近的像素点互相连接起来构成⼀个封闭的轮廓,封闭性是分⽔岭算法的⼀个重要特征。
API介绍void watershed( InputArray image, InputOutputArray markers );参数说明:image: 必须是⼀个8bit 3通道彩⾊图像矩阵序列markers: 在执⾏分⽔岭函数watershed之前,必须对第⼆个参数markers进⾏处理,它应该包含不同区域的轮廓,每个轮廓有⼀个⾃⼰唯⼀的编号,轮廓的定位可以通过Opencv中findContours⽅法实现,这个是执⾏分⽔岭之前的要求。
算法会根据markers传⼊的轮廓作为种⼦(也就是所谓的注⽔点),对图像上其他的像素点根据分⽔岭算法规则进⾏判断,并对每个像素点的区域归属进⾏划定,直到处理完图像上所有像素点。
⽽区域与区域之间的分界处的值被置为“-1”,以做区分。
我们将⼀个如何使⽤距离变换和分⽔岭分割相互接触的物体的例⼦。
考虑⼀下下⾯的硬币图像,这些硬币相互接触。
即使你去阈值化它,它也会互相碰触。
我们从找到硬币的⼤概估计值开始。
为此,我们可以利⽤⼤津的⼆值化。
#include<iostream>#include<opencv2\opencv.hpp>using namespace std;using namespace cv;int main() {Mat gray, thresh;Mat img = imread("coins.jpg");cvtColor(img, gray, COLOR_BGR2GRAY);threshold(gray, thresh, 0, 255, THRESH_BINARY_INV+CV_THRESH_OTSU);imshow("Otst阈值图像", thresh);waitKey(0);return 0;}阈值后的图像如下所⽰:现在需要去除图像中任何微⼩的⽩⾊噪声。
车牌识别(⼀)-车牌定位在对车牌识别过程中,常⽤的⽅法有:基于形状、基于⾊调、基于纹理、基于⽂字特征等⽅法。
⾸先基于形状,在车牌中因为车牌为形状规格的矩形,所以⽬的转化为寻找矩形特征,常常是利⽤车牌长宽⽐例特征、占据图像的⽐例等。
基于⾊调,国内的车牌往往是蓝底⽩字,可以采⽤图像的⾊调或者饱和度特征,进⼊⽣成⼆值图,定位车牌位置。
基于纹理特征⾃⼰还没有基础到。
基于⽂字特征往往是根据⽂字轮廓特征进⾏识别,原理是基于相邻⽂字轮廓特征、⽐例进⾏定位车牌位置。
⼀、图像⼆值化正如前⾯⽂章所⾔,⾸先进⾏获取图像⼆值化特征,本⽂采取了根据图像亮度特征,提⾼对⽐度,进⾏可以清晰获取⽂字的图像,为下⼀步的⽂字轮廓识别打好基础。
1.1 算法流程伪代码1、图像转化为HSV图像,获取V通道图像2、提⾼对⽐度3、V图像⾼斯滤波,去除噪声4、图像⼆值化程序源码:def get_colorvalue(image):height, width, shape = image.shapeimage_hsv = np.zeros((height,width), np.uint8)image_hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)image_hue, image_saturation, image_value = cv2.split(image_hsv)return image_valuedef enhance_contrast(image):kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))img_tophat = cv2.morphologyEx(image, cv2.MORPH_TOPHAT,kernel)img_blackhat = cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel)image_plus_tophat = cv2.add(image, img_tophat)image_plus_blackhat_minus_blackhat = cv2.subtract(image_plus_tophat, img_blackhat)return image_plus_blackhat_minus_blackhatdef preprocess(srcimage):image_value = get_colorvalue(srcimage)image_enhance = enhance_contrast(image_value)image_blur = cv2.GaussianBlur(image_enhance, (5,5), 0)# _, image_binary = cv2.threshold(image_blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)_, image_binary = cv2.threshold(image_blur, 100, 255, cv2.THRESH_BINARY )cv2.imwrite('image_binary.png',image_binary)return image_binary1.2 算法分析在实验中在获取通道图像时,发现可以利⽤图像饱和度图像进⾏定位。
基于深度摄像头的障碍物检测(realsense+opencv)前⼏天⽼⼤给了个任务,让我帮slam组写⼀个基于深度摄像头的障碍物检测,捣⿎了两天弄出来了,效果还不错,就在这⾥记⼀下了。
代码的核⼼思路是⾸先通过⼆值化,将⼀⽶之外的安全距离置零不考虑,然后通过开运算去除掉⼀些噪点(这个后来发现不⼀定有必要),在求出所有障碍物的凸包,这个时候要计算⾯积,当⾯积⼩于⼀定的阈值的时候不予考虑,最终输出障碍物的凸包坐标。
//find_obstacle函数是获取深度图障碍物的函数,返回值是每个障碍物凸包的坐标,参数⼀depth是realsense返回的深度图(ushort型),//参数⼆thresh和参数三max_thresh,是⼆值化的参数,参数四是凸包的最⼩有效⾯积,⼩于这个⾯积的障碍物可以视为噪点。
//函数⾸先筛选掉距离⼤于安全距离的点,然后进⾏阀值化和开运算减少⼀下噪点,⽤findContours得到轮廓图,最后⽤convexHull得到每个障碍物的凸包,最后返回坐标//mask_depth函数是对深度图⼆值化,第⼀个参数image是原图,第⼆个参数th是⽬标图,第三个参数throld是最⼤距离,单位是mm,⼤于这个距离//即为安全,不⽤考虑。
#include <iostream>#include <opencv2/core/core.hpp>#include <opencv2/highgui/highgui.hpp>#include "RSWrapper.h"#include "opencv2/imgproc/imgproc.hpp"using namespace std;using namespace cv;void mask_depth(Mat &image,Mat& th,int throld=1000){int nr = image.rows; // number of rowsint nc = image.cols; // number of columnsfor (int i = 0; i<nr; i++){for (int j = 0; j<nc; j++) {if (image.at<ushort>(i, j)>throld)th.at<ushort>(i, j) = 0;}}}vector<vector<Point> > find_obstacle(Mat &depth, int thresh = 20, int max_thresh = 255, int area = 500){Mat dep;depth.copyTo(dep);mask_depth(depth, dep, 1000);dep.convertTo(dep, CV_8UC1, 1.0 / 16);//imshow("color", color);imshow("depth", dep);Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));//核的⼤⼩可适当调整Mat out;//进⾏开操作morphologyEx(dep, out, MORPH_OPEN, element);//dilate(dhc, out, element);//显⽰效果图imshow("opencv", out);Mat src_copy = dep.clone();Mat threshold_output;vector<vector<Point> > contours;vector<Vec4i> hierarchy;RNG rng(12345);/// 对图像进⾏⼆值化threshold(dep, threshold_output, thresh, 255, CV_THRESH_BINARY);//mask_depth(src, threshold_output);/// 寻找轮廓findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));/// 对每个轮廓计算其凸包vector<vector<Point> >hull(contours.size());vector<vector<Point> > result;for (int i = 0; i < contours.size(); i++){convexHull(Mat(contours[i]), hull[i], false);}/// 绘出轮廓及其凸包Mat drawing = Mat::zeros(threshold_output.size(), CV_8UC3);for (int i = 0; i< contours.size(); i++){if (contourArea(contours[i]) < area)//⾯积⼩于area的凸包,可忽略continue;result.push_back(hull[i]);Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); drawContours(drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point()); drawContours(drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point());}imshow("contours", drawing);return result;}int main(int argc, char* argv[]){Mat dhc;Mat dep;int idxImageRes = 1, idxFrameRate = 30;RSWrapper depthCam(idxImageRes, idxImageRes, idxFrameRate, idxFrameRate); if (!depthCam.init()){std::cerr << "Init. RealSense Failure!" << std::endl;return -1;}while (true){//Get RGB-D Imagescv::Mat color, depth;bool ret = depthCam.capture(color, depth);if (!ret) {std::cerr << "Get realsense camera data failure!" << std::endl;break;}vector<vector<Point> > result;result = find_obstacle(depth, 20, 255, 500);if (cvWaitKey(1) == 27)break;}depthCam.release();}。
opencv库常⽤函数常⽤opencv函数:1、cv2.line():画线——参数依次为:图⽚路径,起点和终点坐标值,颜⾊(rgb),线条宽度(像素)2、dst = cvtColor(src,code,dst=None,dstCn=None):颜⾊空间转换函数——参数依次为(原图像,color转化代码,输出图像,输出通道), 返回转换后的图像3、ret, dst = cv2.threshold(src, thresh, maxval, type):固定阈值⼆值化——src:输⼊图,只能输⼊单通道图像,通常来说为灰度图dst:输出图thresh:阈值maxval:当像素值超过了阈值(或者⼩于阈值,根据type来决定),所赋予的值type:⼆值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV4、cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]]) :查找检测物体的轮廓opencv2返回两个值:contours:hierarchy。
注:opencv3会返回三个值,分别是img, countours, hierarchy参数:第⼀个参数是寻找轮廓的图像;第⼆个参数表⽰轮廓的检索模式,有四种(本⽂介绍的都是新的cv2接⼝):cv2.RETR_EXTERNAL 表⽰只检测外轮廓cv2.RETR_LIST 检测的轮廓不建⽴等级关系cv2.RETR_CCOMP 建⽴两个等级的轮廓,上⾯的⼀层为外边界,⾥⾯的⼀层为内孔的边界信息。
如果内孔内还有⼀个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE 建⽴⼀个等级树结构的轮廓。
第三个参数method为轮廓的近似办法cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1cv2.CHAIN_APPROX_SIMPLE 压缩⽔平⽅向,垂直⽅向,对⾓线⽅向的元素,只保留该⽅向的终点坐标,例如⼀个矩形轮廓只需4个点来保存轮廓信息cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使⽤teh-Chinl chain 近似算法返回值cv2.findContours()函数返回两个值,⼀个是轮廓本⾝,还有⼀个是每条轮廓对应的属性。
形态学滤波(2):开运算、闭运算、形态学梯度、顶帽、⿊帽⼀、开运算开运算,就是先腐蚀后膨胀的过程数学表达式: dst = open(src,element) = dilate(erode(src, element))开运算可以⽤来消除⼩物体,在纤细点处分离物体,并且在平滑较⼤物体的边界的同时不明显改变其⾯积。
⼆、闭运算闭运算,就是先膨胀后腐蚀的过程数学表达式: dst = open(src,element) = erode(dilate(src, element))闭运算可以⽤来排除⼩型⿊洞(⿊⾊区域)三、形态学梯度形态学梯度,就是膨胀图与腐蚀图之差数学表达式: dst = morph-grad(src,element) = dilate(src, element) - erode(src, element)对⼆值图进⾏这⼀操作可以将团块的边缘突出出来,我们可以⽤形态学梯度来保留物体的边缘轮廓四、顶帽顶帽(礼帽)运算,就是原图像与“开运算”的结果图之差数学表达式: dst = tophat(src,element) = src - open(src,element)因为开运算带来的结果是放⼤了裂缝或者局部低亮度的区域。
因此从原图中减去开运算后的图,得到的效果图突出了⽐原图轮廓周围的区域更明亮的区域,且这⼀操作与选择的核的的⼤⼩相关。
顶帽运算往往⽤来分离⽐临近点亮⼀些的斑块,在⼀幅图像具有⼤幅的背景,⽽微⼩物品⽐较有规律的情况下,可以使⽤顶帽运算进⾏背景提取五、⿊帽⿊帽运算,就是“闭运算”的结果图与原图像之差数学表达式: dst = blackhat(src,element) = close(src,element) - src⿊帽运算后的效果图突出了⽐原图轮廓周围的区域更暗的区域,且这⼀操作和选择的核的⼤⼩相关⿊帽运算⽤来分离⽐临近点暗⼀些的斑块,效果图有着⾮常完美的轮廓六、核⼼函数:morphologyEx()1void morphologyEx( InputArray src, OutputArray dst,2int op, InputArray kernel,3 Point anchor = Point(-1,-1), int iterations = 1,4int borderType = BORDER_CONSTANT,5const Scalar& borderValue = morphologyDefaultBorderValue() );1 #include<opencv2/opencv.hpp>2 #include<iostream>34using namespace std;5using namespace cv;67 Mat g_srcImage, g_dstImage;8int g_nElementShap = MORPH_RECT; //元素结构的形状910//变量接收的TrackBar位置参数11int g_nMaxIterationNum = 10;12int g_nOpenCloseNum = 0;13int g_nErodeDilateNum = 0;14int g_nTopBlackHatNum = 0;1516static void on_OpenClose(int, void *); //回调函数17static void on_ErodeDilate(int, void *);18static void on_TopBlackHat(int, void *);192021int main()22 {23//载⼊原图24 g_srcImage = imread("C:\\Users\\Administrator\\Pictures\\Camera Roll\\05.jpg");25if (!g_srcImage.data) {26 cout << "图⽚载⼊失败!" << endl;27return false;28 }2930//显⽰原始图31 namedWindow("【原始图】");32 imshow("【原始图】", g_srcImage);3334//创建三个窗⼝35 namedWindow("【开运算/闭运算】", 1);36 namedWindow("【腐蚀/膨胀】", 1);37 namedWindow("【顶帽/⿊帽】", 1);3839//分别为三个窗⼝创建滚动条40 createTrackbar("迭代值", "【开运算/闭运算】", &g_nOpenCloseNum, g_nMaxIterationNum * 2 + 1, on_OpenClose);41 createTrackbar("迭代值", "【腐蚀/膨胀】", &g_nErodeDilateNum, g_nMaxIterationNum * 2 + 1, on_ErodeDilate);42 createTrackbar("迭代值", "【顶帽/⿊帽】", &g_nTopBlackHatNum, g_nMaxIterationNum * 2 + 1, on_TopBlackHat); 4344//轮询获取按键信息45while (1)46 {47int c;4849//执⾏回调函数50 on_OpenClose(g_nOpenCloseNum, 0);51 on_ErodeDilate(g_nErodeDilateNum, 0);52 on_TopBlackHat(g_nTopBlackHatNum, 0);5354//获取按键55 c = waitKey(0);5657//按下键盘Q或者ESC,程序退出58if (c == 'q' || c == 27)59break;60//按下键盘按键1,使⽤椭圆(Elliptic)结构元素MORPH_ELLIPSE61if (c == 'a')62 g_nElementShap = MORPH_ELLIPSE;63//按下键盘按键2,使⽤矩形(Rectangle)结构元素MORPH_RECT64if (c == 'b')65 g_nElementShap = MORPH_RECT;66//按下键盘按键3,使⽤⼗字形(Cross-shaped)结构元素MORPH_CROSS67if (c == 'c')68 g_nElementShap = MORPH_CROSS;69//按下键盘按键space,在矩形、椭圆、⼗字形结构元素中循环70if (c == '')71 g_nElementShap = (g_nElementShap + 1) % 3;72 }73return0;74 }75static void on_OpenClose(int, void *) {76//偏移量的定义77int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量78int Absolute_offset = offset > 0 ? offset : -offset; //偏移量的绝对值79//⾃定义核80 Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset)); 8182//进⾏操作83if (offset < 0)84 morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);85else86 morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);8788//显⽰图像89 imshow("【开运算/闭运算】", g_dstImage);90 }9192static void on_ErodeDilate(int, void *) {93int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量94int Absolute_offset = offset > 0 ? offset : -offset; //偏移量的绝对值95//⾃定义核96 Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset)); 9798//进⾏操作99if (offset < 0)100 erode(g_srcImage, g_dstImage, element);101else102 dilate(g_srcImage, g_dstImage, element);103104//显⽰图像105 imshow("【腐蚀/膨胀】", g_dstImage);106 }107108static void on_TopBlackHat(int, void *) {109int offset = g_nOpenCloseNum - g_nMaxIterationNum; //偏移量110int Absolute_offset = offset > 0 ? offset : -offset; //偏移量的绝对值111//⾃定义核112 Mat element = getStructuringElement(g_nElementShap, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset)); 113114//进⾏操作115if (offset < 0)116 morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);117else118 morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);119120//显⽰图像121 imshow("【顶帽/⿊帽】", g_dstImage);122 }123。
使⽤OpenCV实现道路车辆计数的使⽤⽅法今天,我们将⼀起探讨如何基于计算机视觉实现道路交通计数。
在本教程中,我们将仅使⽤Python和OpenCV,并借助背景减除算法⾮常简单地进⾏运动检测。
我们将从以下四个⽅⾯进⾏介绍:1. ⽤于物体检测的背景减法算法主要思想。
2. OpenCV图像过滤器。
3. 利⽤轮廓检测物体。
4. 建⽴进⼀步数据处理的结构。
背景扣除算法有许多不同的背景扣除算法,但是它们的主要思想都很简单。
假设有⼀个房间的视频,在某些帧上没有⼈和宠物,那么此时的视频基本为静态的,我们将其称为背景(background_layer)。
因此要获取在视频上移动的对象,我们只需要:⽤当前帧减去背景即可。
由于光照变化,⼈为移动物体,或者始终存在移动的⼈和宠物,我们将⽆法获得静态帧。
在这种情况下,我们从视频中选出⼀些图像帧,如果绝⼤多数图像帧中都具有某个相同的像素点,则此将像素作为background_layer中的⼀部分。
我们将使⽤MOG算法进⾏背景扣除原始帧代码如下所⽰:import osimport loggingimport logging.handlersimport randomimport numpy as npimport skvideo.ioimport cv2import matplotlib.pyplot as pltimport utils# without this some strange errors happencv2.ocl.setUseOpenCL(False)random.seed(123)# ============================================================================ IMAGE_DIR = "./out"VIDEO_SOURCE = "input.mp4"SHAPE = (720, 1280) # HxW# ============================================================================ def train_bg_subtractor(inst, cap, num=500):'''BG substractor need process some amount of frames to start giving result'''print ('Training BG Subtractor...')i = 0for frame in cap:inst.apply(frame, None, 0.001)i += 1if i >= num:return capdef main():log = logging.getLogger("main")# creting MOG bg subtractor with 500 frames in cache# and shadow detctionbg_subtractor = cv2.createBackgroundSubtractorMOG2(history=500, detectShadows=True)# Set up image source# You can use also CV2, for some reason it not working for mecap = skvideo.io.vreader(VIDEO_SOURCE)# skipping 500 frames to train bg subtractortrain_bg_subtractor(bg_subtractor, cap, num=500)frame_number = -1for frame in cap:if not frame.any():log.error("Frame capture failed, stopping...")breakframe_number += 1utils.save_frame(frame, "./out/frame_%04d.png" % frame_number)fg_mask = bg_subtractor.apply(frame, None, 0.001)utils.save_frame(frame, "./out/fg_mask_%04d.png" % frame_number)# ============================================================================ if __name__ == "__main__":log = utils.init_logging()if not os.path.exists(IMAGE_DIR):log.debug("Creating image directory `%s`...", IMAGE_DIR)os.makedirs(IMAGE_DIR)main()处理后得到下⾯的前景图像去除背景后的前景图像我们可以看出前景图像上有⼀些噪⾳,可以通过标准滤波技术可以将其消除。
在OpenCV中,闭运算可以使用cv::morphologyEx 函数实现。
闭运算通常用于填补物体内部的孔洞或连接邻近的物体。
以下是使用cv::morphologyEx 函数进行闭运算的示例代码:cpp#include <opencv2/opencv.hpp>#include <iostream>int main(){// 读取图像cv::Mat src = cv::imread("image.jpg");if (src.empty()){std::cout << "无法读取图像" << std::endl;return -1;}// 创建一个结构元素,这里使用5x5 的方形矩阵cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));// 进行闭运算cv::Mat dst;cv::morphologyEx(src, dst, cv::MORPH_CLOSE, element);// 显示结果cv::imshow("原始图像", src);cv::imshow("闭运算结果", dst);cv::waitKey(0);return 0;}在上述代码中,cv::morphologyEx 函数的第一个参数是输入图像,第二个参数是输出图像,第三个参数是进行闭运算的标志(这里是cv::MORPH_CLOSE),第四个参数是结构元素。
可以根据需要调整结构元素的大小和形状,以获得不同的效果。
形态学的原理以及应用场景(含源码)转自:摘要:形态学一般指生物学中研究动物和植物结构的一个分支。
用数学形态学(也称图像代数)表示以形态为基础对图像进行分析的数学工具。
基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的。
形态学图像处理的基本运算有:•膨胀和腐蚀(膨胀区域填充,腐蚀分割区域)•开运算和闭运算(开运算去除噪点,闭运算填充内部孔洞)•击中与击不中•顶帽变换,黑帽变换形态学的应用:消除噪声、边界提取、区域填充、连通分量提取、凸壳、细化、粗化等;分割出独立的图像元素,或者图像中相邻的元素;求取图像中明显的极大值区域和极小值区域;求取图像梯度在讲各种形态学操作之前,先来看看结构元素:膨胀和腐蚀操作的核心内容是结构元素。
(后面的开闭运算等重要的也是结构元素的设计,一个合适的结构元素的设计可以带来很好的处理效果OpenCV里面的API介绍:Mat kernel = getStructuringElement(int shape,Size ksize,Point anchor);一,腐蚀和膨胀腐蚀和膨胀是最基本的形态学操作,腐蚀和膨胀都是针对白色部分(高亮部分)而言的。
•膨胀就是使图像中高亮部分扩张,效果图拥有比原图更大的高亮区域(是求局部最大值的操作)•腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的高亮区域(是求局部最小值的操作)膨胀与腐蚀能实现多种多样的功能,主要如下:1、消除噪声2、腐蚀分割(isolate)出独立的图像元素,膨胀在图像中连接(join)相邻的元素。
3、寻找图像中的明显的极大值区域或极小值区域4、求出图像的梯度opencv中膨胀/腐蚀API:(两者相同)void dilate/erode( const Mat& src, //输入图像(任意通道的)opencv实现:Mat src1 = imread("D:/opencv练习图片/腐蚀膨胀.png");图片膨胀:图片[图片上传中...(image-e5cbf7-1637738882548-13)]1️⃣ 腐蚀操作的原理就是求局部最小值的操作,并把这个最小值赋值给参考点指定的像素。
EmguCV常⽤函数总结1 Emgucv常⽤函数总结:2读取图⽚3 Mat SCr = new Mat(Form1.Path, Emgu.CV.CvEnum.LoadImageType.AnyColor);4//根据路径创建指定的灰度图⽚5 Mat scr = new Mat(Form1.Path, Emgu.CV.CvEnum.LoadImageType.Grayscale);6获取灰度//图像类型转换, bgr 转成 gray 类型。
MAT Bw = New MAT7 CvInvoke.CvtColor(SCr, bw, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);8//相当于⼆值化图 --⿊⽩根据⼤⼩10判断为0还是2559 CvInvoke.Threshold(bw,bw,10,255,Emgu.CV.CvEnum.ThresholdType.BinaryInv);10//获取指定区域图⽚ SCr为mat类型11 Rectangle rectangle = new Rectangle(10,10,10,10);12 SCr = SCr.ToImage<Bgr, byte>().GetSubRect(rectangle).Mat;13//将Mat类型转换为Image类型14 Image<Bgr, byte> Su = SCr.ToImage<Bgr, byte>();15 Image<Bgr, byte> Img = new Image<Bgr, byte>(new Bitmap(""));//路径声明16 Image<Bgr, byte> Sub = SCr.ToImage<Bgr, byte>().GetSubRect(rectangle);//指定范围17//指定参数获得结构元素18 Mat Struct_element = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Cross, new Size(3, 3), new Point(-1, -1));19//膨胀20 CvInvoke.Dilate(bw, bw, Struct_element, new Point(1,1),3,Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0, 0, 0));21//腐蚀当Struct_element模型创建不合理或者膨胀腐蚀次数较⼤时可能图像会发⽣偏移22 CvInvoke.Erode(bw, bw, Struct_element, new Point(-1, -1), 3,Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0, 0, 0));23//轮廓提取24 VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();25//筛选后26 CvInvoke.FindContours(bw, contours, null, Emgu.CV.CvEnum.RetrType.List, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);27int ksize = contours.Size;//获取连通区域的个数。
opencv createbackgroundsubtractormog2 参数OpenCV是一个流行的开源计算机视觉库,它提供了各种功能来处理图像和视频。
其中之一是背景建模。
背景建模是一种将场景中动态的物体与静态背景分离的技术。
OpenCV中的`createBackgroundSubtractorMOG2`方法是一种常用的背景建模算法,它使用了高斯混合模型(Gaussian Mixture Model, GMM)来对背景进行建模。
本文将详细解释`createBackgroundSubtractorMOG2`的各种参数,并逐步回答相关问题。
1. 背景建模的概念及应用介绍(200-300字)背景建模是计算机视觉领域中的一项基础技术,用于从视频序列中提取出静态背景。
它通过分析每一帧图像中的像素值,将被运动物体遮挡的背景部分提取出来。
这项技术在许多领域都有广泛的应用,例如视频监控、运动检测、虚化背景等。
2. `createBackgroundSubtractorMOG2`方法的参数介绍(500-600字)`createBackgroundSubtractorMOG2`方法是OpenCV中的一个函数,用于创建一个基于高斯混合模型的背景建模器。
该方法有多个参数,下面将逐一介绍这些参数的含义和作用。
- `history`参数用于指定需要考虑的过去帧的数量。
它定义了模型中保留的观察帧的数量。
这个参数的值越大,模型将考虑更长时间内的像素值,从而更好地适应背景的变化。
默认值为500。
- `varThreshold`参数用于指定高斯分布的阈值。
当像素值与背景差异超过这个阈值时,该像素被认为是前景对象的一部分。
较小的值可以捕捉到更小的变化,但也可能会引入噪声。
默认值为16。
- `detectShadows`参数用于指定算法是否检测阴影。
如果设置为True,则会检测并标记出阴影区域。
默认值为True。
- `shadowValue`参数用于指定阴影像素的值。
肤色检测算法肤色Gaussian模型//rgbImg:输入RGB图像//value:输入阈值(value>0&&value<1)//value描述了某一像素值为肤色的概率//value推荐值使用0.2~0.5//mask:输出二值化图像//涉及矩阵、指数计算,运算量比较大void skinGaussian(Mat& rgbImg,double value,Mat& mask){mask = Mat::zeros(rgbImg.size(), CV_8UC1);Mat imageYcrcb;cvtColor(rgbImg, imageYcrcb, COLOR_BGR2YCrCb);Mat x(2, 1, CV_32FC1);//肤色统计数据Mat u = (Mat_<float>(2, 1) << 117.4361, 156.5599);Mat s = (Mat_<float>(2, 2) << 160.1301, 12.1430,12.1430, 299.4574);//肤色检测for (int i = 0; i < imageYcrcb.rows; i++){for (int j = 0; j < imageYcrcb.cols; j++){Vec3b temp = imageYcrcb.at<Vec3b>(i, j);//读取Cr,Cb值x.at<float>(0, 0) = temp[2];x.at<float>(1, 0) = temp[1];//矩阵运算Mat temp2 = (x - u).t()*s.inv()*(x - u);double samility = exp(temp2.at<float>(0, 0)*(-0.5));if (samility>value){mask.at<uchar>(i, j) = 255;}}}//闭运算,消除二值图像的孔洞Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MorphTypes::MORPH_CLOSE, kernel);}肤色椭圆模型//rgbImg:输入的RGB图像//mask:输出的二值化图像,非0区域为检测结果void skinEllipse(Mat& rgbImg,Mat& mask){//初始化掩膜//掩膜:二值化图像,非0区域为保留的感兴趣区域mask = Mat::zeros(rgbImg.size(), CV_8UC1);//RGB->YCrCb,opencv中默认将RGB图像存储为BGRMat YcrcbImg;cvtColor(rgbImg, YcrcbImg, COLOR_BGR2YCrCb);//椭圆肤色模型Mat skinCrCb = Mat::zeros(256, 256, CV_8UC1);ellipse(skinCrCb, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255), -1);//利用椭圆模型进行肤色检测for (int i = 0; i < rgbImg.rows; i++){uchar* p = (uchar*)mask.ptr<uchar>(i);Vec3b* ycrcb = (Vec3b*)YcrcbImg.ptr<Vec3b>(i);for (int j = 0; j < rgbImg.cols; j++){if (skinCrCb.at<uchar>(ycrcb[j][1],ycrcb[j][2])>0){p[j] = 255;}}}//闭运算,消除二值图像的孔洞Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MorphTypes::MORPH_CLOSE, kernel);}基于HSV颜色空间的肤色检测//rgbImg:输入的RGB图像//mask:输出的二值化图像,非0区域为检测结果void skinBasedOnHSV(Mat& rgbImg, Mat& mask){//初始化掩膜mask = Mat::zeros(rgbImg.size(), CV_8UC1);//RGB->HSVMat hsvImg;cvtColor(rgbImg, hsvImg, COLOR_BGR2HSV);//HSV分割经验阈值①Scalar hsv_min1(0, 30, 80);Scalar hsv_max1(20, 150, 255);//HSV分割经验阈值②Scalar hsv_min2(0, 10, 60);Scalar hsv_max2(20, 150, 255);//HSV值处于阈值之间的区域保留inRange(hsvImg, hsv_min2, hsv_max2, mask);Mat skinImg;//闭运算,消除二值图像的孔洞Mat kernel = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));morphologyEx(mask, mask, MorphTypes::MORPH_CLOSE, kernel);rgbImg.copyTo(skinImg, mask);}。
图像处理开闭操作(17)⼀定义1 开操作: 是图像的轮廓变得光滑,断开的较窄的狭颈和消除细的突出物. 使结构元B对集合A进⾏开操作,定义为: A○B=(A⊖B)⊕B含义:先⽤B对A进⾏腐蚀,然后⽤B对结果进⾏膨胀。
2 闭操作:同样使图像轮廓变得光滑,但与开操作相反,他能弥合狭窄的间断和细⼩的沟壑,消除⼩的空洞,并填补轮廓线中的裂痕.使⽤结构元B对集合A进⾏闭操作,定义为 A·B=(A⊕B)⊖B结构元集合A原始图⽚2 ⼏何解释1)开操作的何解释 A○B的边界由B中的点建⽴ 当B在A的边界内侧滚动时,B所能到达的A的边界的最远点。
(2)闭操作的⼏何解释 A•B的边界由B中的点建⽴ B在A的边界外侧滚动 满⾜〖(B)〗_z⋂A≠”Ø” 的所有点的集合3 相关函数函数原型morphologyEx( src,op,kernel,dst=None,anchor=None,iterations=None,borderType=None,borderValue=None)参数介绍. @param src Source image. The number of channels can be arbitrary. The depth should be one of. CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. 来源图⽚。
通道数可以是任意的。
深度应该是其中之⼀。
CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
. @param op Type of a morphological operation, see #MorphTypes 形态操作的类型 cv.MORPH_OPEN, cv.MORPH_CLOSE. @param kernel Structuring element. It can be created using #getStructuringElement. 内核(element). @param anchor Anchor position with the kernel. Negative values mean that the anchor is at the. kernel center. ⽤内核锚定位置。
morphologyex函数morphologyex函数是一种形态学操作函数,是OpenCV中的一种函数。
它可以进行图像的腐蚀、膨胀、开运算、闭运算等操作,常用于图像处理、数字图像分析和计算机视觉等领域。
首先,腐蚀操作是一种将图像中较小的元素缩小或消除的方法,可以使对象的边界缩小或断裂,即可以将目标内部分离出来,或是去掉目标的凹陷部分。
其基本原理是用一个结构元素与图像的每个像素点进行比较,并将结构元素超出像素点的部分舍弃,最终得到一个新的图像。
语法格式是:cv2.morphologyEx(src, op, kernel)其中,src参数是要进行腐蚀操作的图像,op参数是要进行的形态学操作,kernel 参数是结构元素,它的大小和形状决定了形态操作的效果。
膨胀操作是将图像中较小的元素扩大或连接起来的方法,可以将图像中的空隙填充,或将目标的凹凸部分连接起来,其基本原理是用一个结构元素与图像的每个像素点进行比较,并将结构元素覆盖到像素点上,最终得到一个新的图像。
语法格式是:cv2.morphologyEx(src, op, kernel)其中,src参数是要进行膨胀操作的图像,op参数是要进行的形态学操作,kernel 参数是结构元素,它的大小和形状决定了形态操作的效果。
开运算是将图像先进行腐蚀操作再进行膨胀操作的方法,可以消除小的物体和连通物体的细小分支。
其基本原理是先将图像进行腐蚀操作,然后将结果进行膨胀操作。
语法格式是:cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)其中,src参数是要进行开运算的图像,cv2.MORPH_OPEN是表示进行开运算操作,kernel参数是结构元素,它的大小和形状决定了形态操作的效果。
闭运算是将图像先进行膨胀操作再进行腐蚀操作的方法,可以消除小的黑洞和孔洞。
其基本原理是先将图像进行膨胀操作,然后将结果进行腐蚀操作。
语法格式是:cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)其中,src参数是要进行闭运算的图像,cv2.MORPH_CLOSE是表示进行闭运算操作,kernel参数是结构元素,它的大小和形状决定了形态操作的效果。
∙Open Source Computer Vision Library ∙∙ 论坛 ∙ 商业 ∙ 专题 ∙ 讲座 ∙ 例程 ∙ 安装 ∙ 常见问题 ∙ 函数说明Cv 图像处理Wikipedia ,自由的百科全书注意:本章描述图像处理和分析的一些函数。
大多数函数都是针对两维象素数组的,这里,我们称这些数组为“图像”,但是它们不一定非得是IplImage 结构,也可以是CvMat 或者CvMatND 结构。
目录[隐藏]∙ 1 梯度、边缘和角点o 1.1 Sobelo 1.2 Laplaceo 1.3 Cannyo 1.4 PreCornerDetecto 1.5 CornerEigenValsAndVecso 1.6 CornerMinEigenValo 1.7 CornerHarriso 1.8 FindCornerSubPixo 1.9 GoodFeaturesToTrack∙ 2 采样、插值和几何变换o 2.1 InitLineIteratoro 2.2 SampleLineo 2.3 GetRectSubPixo 2.4 GetQuadrangleSubPixo 2.5 Resizeo 2.6 WarpAffineo 2.7 GetAffineTransformo 2.8 2DRotationMatrixo 2.9 WarpPerspectiveo 2.10 WarpPerspectiveQMatrixo 2.11 GetPerspectiveTransformo 2.12 Remapo 2.13 LogPolar∙ 3 形态学操作o 3.1 CreateStructuringElementExo 3.2 ReleaseStructuringElemento 3.3 Erodeo 3.4 Dilateo 3.5 MorphologyEx∙ 4 滤波器与色彩空间变换o 4.1 Smootho 4.2 Filter2Do 4.3 CopyMakeBordero 4.4 Integralo 4.5 CvtColoro 4.6 Thresholdo 4.7 AdaptiveThreshold∙ 5 金字塔及其应用o 5.1 PyrDowno 5.2 PyrUp∙ 6 连接部件o 6.1 CvConnectedCompo 6.2 FloodFillo 6.3 FindContourso 6.4 StartFindContourso 6.5 FindNextContouro 6.6 SubstituteContouro 6.7 EndFindContourso 6.8 PyrSegmentationo 6.9 PyrMeanShiftFilteringo 6.10 Watershed∙7 图像与轮廓矩o7.1 Momentso7.2 GetSpatialMomento7.3 GetCentralMomento7.4 GetNormalizedCentralMomento7.5 GetHuMoments∙8 特殊图像变换o8.1 HoughLineso8.2 HoughCircleso8.3 DistTransformo8.4 Inpaint∙9 直方图o9.1 CvHistogramo9.2 CreateHisto9.3 SetHistBinRangeso9.4 ReleaseHisto9.5 ClearHisto9.6 MakeHistHeaderForArrayo9.7 QueryHistValue_1Do9.8 GetHistValue_1Do9.9 GetMinMaxHistValueo9.10 NormalizeHisto9.11 ThreshHisto9.12 CompareHisto9.13 CopyHisto9.14 CalcHisto9.15 CalcBackProjecto9.16 CalcBackProjectPatcho9.17 CalcProbDensityo9.18 EqualizeHist∙10 匹配o10.1 MatchTemplateo10.2 MatchShapeso10.3 CalcEMD2[编辑]梯度、边缘和角点[编辑]Sobel使用扩展 Sobel 算子计算一阶、二阶、三阶或混合图像差分void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );src输入图像.dst输出图像.xorderx 方向上的差分阶数yordery 方向上的差分阶数aperture_size扩展 Sobel 核的大小,必须是 1, 3, 5 或 7。
在OpenCV中,水尺识别可以通过多种方法实现,包括边缘检测、阈值处理、形态学操作等。
以下是一个简单的例子,使用了Canny边缘检测和阈值处理进行水尺识别。
请注意,这个代码只是一个基本的示例,可能需要根据实际应用场景进行修改和优化。
python复制代码import cv2import numpy as np# 加载图像image = cv2.imread('water_level.jpg')# 转换为灰度图像gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# Canny边缘检测edges = cv2.Canny(gray, 50, 150, apertureSize=3)# 阈值处理_, thresh = cv2.threshold(edges, 30, 255, cv2.THRESH_BINARY)# 形态学操作消除噪声kernel = np.ones((3,3), np.uint8)opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2)# 找到轮廓contours, _ = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 在原图上画出轮廓cv2.drawContours(image, contours, -1, (0,255,0), 3)# 显示图像cv2.imshow('Water Level', image)cv2.waitKey(0)cv2.destroyAllWindows()这段代码首先加载一张图像,然后将其转换为灰度图像。
接着,使用Canny边缘检测来找出图像中的边缘,然后使用阈值处理将这些边缘二值化。
形态学操作被用来消除噪声,然后找到并画出这些边缘的轮廓。
图像处理09对象检测--分⽔岭算法对象测量对象测量可以帮助我们进⾏矩阵计算:获取弧长与⾯积多边形拟合计算图⽚对象中⼼多边形拟合步骤:读取图⽚转换成灰度图⼆值化轮廓检测计算轮廓周长多边形拟合格式:cv2.approxPolyDP(curve, epsilon, closed, approxCurve=None)1参数:curve: 输⼊轮廓epsilon: 逼近曲率, 越⼩表⽰相似逼近越厉害closed: 是否闭合import cv2from matplotlib import pyplot as plt# 读取图⽚image = cv2.imread("tx.png")image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# ⼆值化ret, thresh = cv2.threshold(image_gray, 127, 255, cv2.THRESH_OTSU)# 计算轮廓contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)# 轮廓近似perimeter = cv2.arcLength(contours[0], True)approx = cv2.approxPolyDP(contours[0], perimeter * 0.1, True)# 绘制轮廓result1 = cv2.drawContours(image.copy(), contours, 0, (0, 0, 255), 2)result2 = cv2.drawContours(image.copy(), [approx], -1, (0, 0, 255), 2)# 图⽚展⽰f, ax = plt.subplots(1, 2, figsize=(12, 8))# ⼦图ax[0].imshow(cv2.cvtColor(result1, cv2.COLOR_BGR2RGB))ax[1].imshow(cv2.cvtColor(result2, cv2.COLOR_BGR2RGB))# 标题ax[0].set_title("contour")ax[1].set_title("approx")plt.show()计算对象中⼼cv2.moments()可以帮助我们得到轮距, 从⽽进⼀步计算图⽚对象的中⼼.格式:cv2.moments(array, binaryImage=None)1参数:array: 轮廓binaryImage: 是否把 array 内的⾮零值都处理为 1, 默认为 Noneimport numpy as npimport cv2# 读取图⽚image = cv2.imread("tx.png")image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# ⼆值化ret, thresh = cv2.threshold(image_gray, 0, 255, cv2.THRESH_OTSU)# 获取轮廓contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 遍历每个轮廓for i, contour in enumerate(contours):# ⾯积area = cv2.contourArea(contour)# 外接矩形x, y, w, h = cv2.boundingRect(contour)# 获取论距mm = cv2.moments(contour)print(mm, type(mm)) # 调试输出 (字典类型)# 获取中⼼cx = mm["m10"] / mm["m00"]cy = mm["m01"] / mm["m00"]# 获取cv2.circle(image, (np.int(cx), np.int(cy)), 3, (0, 255, 255), -1)cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)# 图⽚展⽰cv2.imshow("result", image)cv2.waitKey(0)cv2.destroyAllWindows()# 保存图⽚cv2.imwrite("result1.jpg", image)分⽔岭算法分⽔岭算法 (Watershed Algorithm) 是⼀种图像区域分割算法. 在分割的过程中, 分⽔岭算法会把跟临近像素间的相似性作为重要的根据.分⽔岭分割流程:1. 读取图⽚2. 转换成灰度图3. ⼆值化4. 距离变换5. 寻找种⼦6. ⽣成 Marker7. 分⽔岭变换连通域连通域 (Connected Components) 指的是图像中具有相同像素且位置相邻的前景像素点组成的图像区域.cv2.connectedComponents(image, labels=None, connectivity=None, ltype=None)1参数:image: 输⼊图像, 必须是 uint8 ⼆值图像labels 图像上每⼀像素的标记, ⽤数字 1, 2, 3 表⽰分⽔岭算法会根据 markers 传⼊的轮廓作为种⼦, 对图像上其他的像素点根据分⽔岭算法规则进⾏判断, 并对每个像素点的区域归属进⾏划定. 区域之间的分界处的值被赋值为 -1. cv2.watershed(image, markers)参数:image: 输⼊图像markers: 种⼦, 包含不同区域的轮廓import numpy as npimport cv2from matplotlib import pyplot as pltdef watershed(image):"""分⽔岭算法"""# 卷积核kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))# 均值迁移滤波blur = cv2.pyrMeanShiftFiltering(image, 10, 100)# 转换成灰度图image_gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)# ⼆值化ret1, thresh1 = cv2.threshold(image_gray, 0, 255, cv2.THRESH_OTSU)# 开运算open = cv2.morphologyEx(thresh1, cv2.MORPH_OPEN, kernel, iterations=2)# 膨胀dilate = cv2.dilate(open, kernel, iterations=3)# 距离变换dist = cv2.distanceTransform(dilate, cv2.DIST_L2, 3)dist = cv2.normalize(dist, 0, 1.0, cv2.NORM_MINMAX)print(dist.max())# ⼆值化ret2, thresh2 = cv2.threshold(dist, dist.max() * 0.6, 255, cv2.THRESH_BINARY)thresh2 = np.uint8(thresh2)# 分⽔岭计算unknown = cv2.subtract(dilate, thresh2)ret3, component = cv2.connectedComponents(thresh2)print(ret3)# 分⽔岭计算markers = component + 1markers[unknown == 255] = 0result = cv2.watershed(image, markers=markers)image[result == -1] = [0, 0, 255]# 图⽚展⽰image_show((image, blur, image_gray, thresh1, open, dilate), (dist, thresh2, unknown, component, markers, image)) return imagedef image_show(graph1, graph2):"""绘制图⽚"""# 图像1original, blur, gray, binary1, open, dilate = graph1# 图像2dist, binary2, unknown, component, markers, result = graph2f, ax = plt.subplots(3, 2, figsize=(12, 16))# 绘制⼦图ax[0, 0].imshow(cv2.cvtColor(original, cv2.COLOR_BGR2RGB))ax[0, 1].imshow(cv2.cvtColor(blur, cv2.COLOR_BGR2RGB))ax[1, 0].imshow(gray, "gray")ax[1, 1].imshow(binary1, "gray")ax[2, 0].imshow(open, "gray")ax[2, 1].imshow(dilate, "gray")# 标题ax[0, 0].set_title("original")ax[0, 1].set_title("image blur")ax[1, 0].set_title("image gray")ax[1, 1].set_title("image binary1")ax[2, 0].set_title("image open")ax[2, 1].set_title("image dilate")plt.show()f, ax = plt.subplots(3, 2, figsize=(12, 16))# 绘制⼦图ax[0, 0].imshow(dist, "gray")ax[0, 1].imshow(binary2, "gray")ax[1, 0].imshow(unknown, "gray")ax[1, 1].imshow(component, "gray")ax[2, 0].imshow(markers, "gray")ax[2, 1].imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))# 标题ax[0, 0].set_title("image distance")ax[0, 1].set_title("image binary2")ax[1, 0].set_title("image unknown")ax[1, 1].set_title("image component")ax[2, 0].set_title("image markers")ax[2, 1].set_title("result")plt.show()if __name__ == "__main__":# 读取图⽚image = cv2.imread("girl.png")# 分⽔岭算法result = watershed(image)# 保存结果cv2.imwrite("result.png", result)。
morphologyex 参数
在图像处理中,MorphologyEx是一种常用的图像处理技术,用于图像的形态学操作。
形态学操作是基于图像的形状和结构来进行处理的。
MorphologyEx函数通常用于图像的腐蚀、膨胀、开运算、闭运算等操作。
下面我会从不同的角度来解释MorphologyEx函数的参数。
1. 原始图像,MorphologyEx函数的第一个参数通常是输入的原始图像,这是需要进行形态学操作的图像。
2. 目标图像,MorphologyEx函数的第二个参数是输出的目标图像,这是进行形态学操作后得到的结果图像。
3. 形态学操作类型,MorphologyEx函数的第三个参数是形态学操作的类型,可以是腐蚀、膨胀、开运算、闭运算等。
4. 结构元素,MorphologyEx函数的第四个参数是结构元素,它定义了进行形态学操作时使用的模板形状和大小。
5. 锚点,MorphologyEx函数的第五个参数是锚点,它指定了
结构元素的锚点位置,通常位于结构元素的中心。
6. 迭代次数,MorphologyEx函数的第六个参数是迭代次数,
用于指定形态学操作的迭代次数,可以对形态学操作进行多次迭代
处理。
通过合理设置这些参数,可以对图像进行不同形式的形态学操作,从而达到去噪、边缘检测、图像增强等目的。
在实际应用中,
根据具体的图像处理需求,可以灵活调整MorphologyEx函数的参数,以获得最佳的处理效果。