opencv blur cvtColor split inRange bitwise_and blur clone

本文详细介绍了一种图像处理流程,包括使用OpenCV进行图像的高斯模糊、颜色空间转换(从RGB到HSV)、图像通道分离及阈值处理等操作。通过对图像不同颜色通道的应用,实现了特定颜色范围内的像素提取。
cv::Mat dsc(img_rgb.size(), CV_8U, cv::Scalar(0));    //分离 
cv::Mat hsv1(img_rgb.size(), CV_8U, cv::Scalar(0));

cv::Mat tmpH1(img_rgb.size(), CV_8U, cv::Scalar(0));
cv::Mat tmpH4(img_rgb.size(), CV_8U, cv::Scalar(0));
cv::Mat tmpH2(img_rgb.size(), CV_8U, cv::Scalar(0));
cv::Mat tmpH3(img_rgb.size(), CV_8U, cv::Scalar(0)); 

blur(img_rgb, img_rgb, cv::Size(3, 3));         //高斯模糊 

cvtColor(img_rgb, hsv1, CV_BGR2HSV);    //颜色转换 

vector<cv::Mat> mv;
split(hsv1, mv);                                             //分为3个通道 


inRange(mv[0], Scalar(10., 0.0, 0, 0), Scalar(100, 0.0, 0, 0), tmpH1);
inRange(mv[1], Scalar(20., 0.0, 0, 0), Scalar(110, 0.0, 0, 0), tmpH2);
inRange(mv[2], Scalar(30., 0.0, 0, 0), Scalar(120.0, 0.0, 0, 0), tmpH3);

bitwise_and(tmpH3, tmpH2, tmpH2);
bitwise_and(tmpH1, tmpH2, tmpH1);

blur(tmpH1,tmpH1,Size(3,3));           //高斯模糊 


dsc = tmpH1.clone();    

               

dsc blur(dsc, dsc, Size(3, 3));           //高斯模糊

imshow("", dsc);


Mat srcImg;  
Mat imgB,imgG,imgR;  
Mat mergeImg;  

vector<Mat> channels;          //Mat向量容器保存拆分后的数据  
  
assert(srcImg.data!=NULL);  //判断文件加载是否正确  
      
split(srcImg,channels);          //通道的拆分  
      
imgB = channels.at(0);  
   
imgG = channels.at(1);  
  
imgR = channels.at(2);  
  
merge(channels,mergeImg);  //对拆分的通道数据合并
  

bool c = false; int num = 0; Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9)); Mat colour_discern(Mat img) { Mat hsv, mask, res; Mat mask_red1, mask_red2, mask_red, mask_blue, combined_mask; cvtColor(img, hsv, COLOR_BGR2HSV); inRange(hsv, Scalar(0, 120, 70), Scalar(10, 255, 255), mask_red1); inRange(hsv, Scalar(160, 120, 70), Scalar(180, 255, 255), mask_red2); bitwise_or(mask_red1, mask_red2, mask_red); inRange(hsv, Scalar(100, 120, 70), Scalar(130, 255, 255), mask_blue); bitwise_or(mask_blue, mask_red, combined_mask); bitwise_and(img, img, res, combined_mask); return res; } int calculate_area(Mat img_color, double thresh) { Mat dst2, edges, gray; vector<vector<Point>> contours; vector<Vec4i> hierarchy; vector<vector<Point>> filtered_contours; cvtColor(img_color, gray, COLOR_BGR2GRAY); GaussianBlur(gray, gray, Size(7, 7), 5, 0); adaptiveThreshold(gray, edges, 254, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, 3); dilate(edges, dst2, kernel, Point(-1, -1), 4); findContours(dst2, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE); for (const auto& contour : contours) { double area = fabs(contourArea(contour)); if (area > thresh) { filtered_contours.push_back(contour); } } for (size_t i = 0; i < filtered_contours.size(); i++) { drawContours(img_color, filtered_contours, static_cast<int>(i), Scalar(0, 0, 0), 10); Rect rect = boundingRect(filtered_contours[i]); rectangle(img_color, rect, Scalar(0, 0, 255), 7); putText(img_color, to_string(contourArea(filtered_contours[i])), Point(rect.x + (rect.width / 2), rect.y + (rect.height / 2)), FONT_HERSHEY_COMPLEX, 0.4, Scalar(255, 255, 255), 1); c = true; } return 0; } int main() { SetConsoleOutputCP(65001); VideoCapture cap(0); if (!cap.isOpened()) { cout << "摄像头未打开"; return -1; } while (true) { Mat img_org, img_colour; cap.read(img_org); img_colour = colour_discern(img_org); calculate_area(img_colour, 500.0); imshow("img_colour", img_colour); imshow("img", img_org); num++; if (num == 5 && c) { cout << "识别到颜色:" << endl; num = 0; } else { c = false; } if (waitKey(1) == 27) break; } return 0; } 在这段代码的基础上修改添加颜色识别到蓝色红色并且只画出最大面积轮廓
最新发布
11-16
#include <opencv2/opencv.hpp> using namespace cv; using namespace std; std::vector<cv::Mat> landmarrk_templates; void drawPic(Mat pic, Mat &output, int x = 0, int y = 140, int width = 100, int height = 100) { cv::resize(pic, pic, cv::Size(width, height)); if (pic.channels() == 1) { cv::cvtColor(pic, pic, cv::COLOR_GRAY2BGR); } cv::Rect roi(cv::Point(x, y), pic.size()); if (roi.x >= 0 && roi.y >= 0 && roi.x + roi.width <= output.cols && roi.y + roi.height <= output.rows) { pic.copyTo(output(roi)); } else { if (roi.x + roi.width > output.cols) { roi.width = output.cols - roi.x; } if (roi.y + roi.height > output.rows) { roi.height = output.rows - roi.y; } cv::Rect srcRoi(0, 0, roi.width, roi.height); cv::Mat srcCropped = pic(srcRoi); srcCropped.copyTo(output(roi)); } } int getTime() { return cv::getTickCount() / cv::getTickFrequency(); } void initTemplates() { landmarrk_templates.push_back( cv::imread("img/both.png", cv::IMREAD_GRAYSCALE)); landmarrk_templates.push_back( cv::imread("img/left.png", cv::IMREAD_GRAYSCALE)); landmarrk_templates.push_back( cv::imread("img/right.png", cv::IMREAD_GRAYSCALE)); landmarrk_templates.push_back( cv::imread("img/light.png", cv::IMREAD_GRAYSCALE)); for (auto &img : landmarrk_templates) { cv::bitwise_not(img, img); } } pair<double, double> process(const Mat &img) { Mat result_img = img.clone(); static int height = img.rows; static int width = img.cols; Mat gray; cvtColor(img, gray, COLOR_BGR2GRAY); Mat binary; threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU); // 检测斑马线 bool now_black = false; bool last_black = false; int chang_count = 0; for (int i = width * 0.3; i < width * 0.7; i += 5) { now_black = binary.at<uchar>(height - 10, i) == 0; if (last_black != now_black) { last_black = now_black; chang_count++; } } if (chang_count > 6) { cout << "检测到斑马线,停车3s" << endl; return {0, 0}; } // 截取binary中间一片区域 cv::Rect mid_region(80, 60, 160, 120); float black_ratio = 1.0f - (countNonZero(binary(mid_region))) / (float)mid_region.area(); // cout << "黑色比例: " << black_ratio << endl; if (black_ratio > 0.2) // 黑色多,有地标 { cv::Mat hsv_img; cv::cvtColor(img, hsv_img, cv::COLOR_BGR2HSV); cv::Mat mask; cv::inRange(hsv_img, cv::Scalar(95, 100, 0), cv::Scalar(130, 255, 255), mask); // 蓝色 cv::Mat bull_img; cv::bitwise_and(img, img, bull_img, mask); // 提取处蓝色部分 cv::Mat gray_bull_img; cv::cvtColor(bull_img, gray_bull_img, cv::COLOR_BGR2GRAY); std::vector<std::vector<cv::Point>> contours; cv::findContours(gray_bull_img, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); cv::Mat filled_mask = cv::Mat::zeros(img.size(), CV_8UC1); contours.erase( std::remove_if(contours.begin(), contours.end(), [=](const std::vector<cv::Point> &contour) { const int tolerance = 10; Rect rect = boundingRect(contour); if (rect.x <= tolerance || rect.y + rect.width >= width - tolerance || rect.y <= tolerance || rect.y + rect.height >= height - tolerance) return true; else return false; }), contours.end()); cv::drawContours(filled_mask, contours, -1, cv::Scalar(255), cv::FILLED); // 将所有闭合蓝色图标填充起来,作为遮罩选中 // drawPic(filled_mask, result_img); // debug cv::Mat icon_img, white_img; cv::bitwise_and(img, img, icon_img, filled_mask); cv::cvtColor(icon_img, icon_img, cv::COLOR_BGR2GRAY); threshold(icon_img, white_img, 0, 255, THRESH_BINARY | THRESH_OTSU); // 找出白色部分 cv::findContours(white_img, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); std::vector<std::vector<cv::Point>> filtered_contours; for (const auto &contour : contours) { double perimeter = cv::arcLength(contour, true); if (perimeter > 100) { filtered_contours.push_back(contour); } } cv::Mat landmark_img = cv::Mat::zeros(img.size(), CV_8UC1); cv::drawContours(landmark_img, filtered_contours, -1, cv::Scalar(255), cv::FILLED); // 过滤高光 std::vector<cv::Point> non_zero_points; cv::findNonZero(landmark_img, non_zero_points); if (!non_zero_points.empty()) { cv::Rect bounding_rect = cv::boundingRect(non_zero_points); if (bounding_rect.width * bounding_rect.height > 800) { landmark_img = landmark_img(bounding_rect); drawPic(landmark_img, result_img); // debug int min_diff = landmark_img.size().area(); int match_index = -1; int confidence = 0.0; for (size_t i = 0; i < landmarrk_templates.size(); ++i) { cv::Mat resized_template; cv::resize(landmarrk_templates[i], resized_template, landmark_img.size()); cv::Mat diff; cv::absdiff(resized_template, landmark_img, diff); int sum_diff = cv::countNonZero(diff); if (sum_diff < min_diff) { min_diff = sum_diff; match_index = i; confidence = 100 - ((float)sum_diff / (float)(landmarrk_templates[i].rows * landmarrk_templates[i].cols)) * 100.0; } } if (match_index != -1 && confidence > 40) { std::cout << "找到地标: " << match_index << " : " << confidence << "%" << std::endl; cv::Mat i = landmarrk_templates[match_index]; cv::rectangle(i, cv::Point(0, 0), cv::Point(i.cols - 1, i.rows - 1), 255, 2); drawPic(i, result_img, bounding_rect.x, bounding_rect.y, 40, 40); cout << "停车3s" << endl; } } } } } int main() { initTemplates(); cv::VideoCapture cap; cap.open(0); if (!cap.isOpened()) { std::cerr << "打开摄像头失败!" << std::endl; return 0; } cap.set(cv::CAP_PROP_FRAME_WIDTH, 320); cap.set(cv::CAP_PROP_FRAME_HEIGHT, 240); cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); cap.set(cv::CAP_PROP_FPS, 60); cap.set(cv::CAP_PROP_AUTO_EXPOSURE, 1); // 0.25 1 都有可能 cap.set(cv::CAP_PROP_EXPOSURE, 100); // 有些摄像头-8能用,有些又是100能用 while (1) { cv::Mat image; cap.read(image); process(image); } return 0; }解释一下这个代码
05-19
int find_line(void) //循迹线程 { // 初始化程序 //UI_init(); VideoCapture capture; capture.open(0); if (!capture.isOpened()) { cout << "Can not open camera" << endl; return -1; } else cout << "camera open successful" << endl; capture.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G')); capture.set(cv::CAP_PROP_FPS, 30); capture.set(cv::CAP_PROP_FRAME_WIDTH, 320); capture.set(cv::CAP_PROP_FRAME_HEIGHT, 240); this_thread::sleep_for(chrono::milliseconds(1000)); //让图像稳定 cout << "Program started" << endl; while (1) { capture >> img; /* if (start_flag == 1) { cvtColor(img, img_HSV, COLOR_BGR2HSV); Scalar HSV_L = Scalar(100, 43, 46); Scalar HSV_H = Scalar(124, 255, 255); inRange(img_HSV, HSV_L, HSV_H, img_HSV_mask); Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); morphologyEx(img_HSV_mask,img_HSV_mask, MORPH_OPEN, kernel); morphologyEx(img_HSV_mask, img_HSV_mask, MORPH_CLOSE, kernel); if (find_blue_card_flag == 0)find_blue_card(); else find_blue_card_remove(); } else { img_per = per_wt(img); Mat HLS_Lresult = HLS_Lthresh(img_per, HSL_Lmin, HSL_Lmax); Mat LAB_Bresult = LAB_BThreshold(img_per, LAB_Bmin, LAB_Bmax); img_combined = combineThresholds(HLS_Lresult, LAB_Bresult); Mat white_image(img.size(), img.type(), Scalar::all(255)); LaneData lanes = slidingWindow(img_combined); lanes.left_fit = polyFit(lanes.left_points); lanes.right_fit = polyFit(lanes.right_points); if (lanes.left_fit.size() != 3 || lanes.right_fit.size() != 3) { if(lanes.left_fit.size() != 3)center_x=lanes.right_fit[0] * line_y * line_y + lanes.right_fit[1]* line_y + lanes.right_fit[2]-rail_width_pix; if(lanes.right_fit.size()!= 3)center_x=lanes.left_fit[0] * line_y * line_y + lanes.left_fit[1]* line_y + lanes.left_fit[2]+rail_width_pix; cout<<center_x<<endl; } if (lanes.left_fit.size() == 3 && lanes.right_fit.size() == 3) { center_x=(lanes.right_fit[0] * line_y * line_y + lanes.right_fit[1]* line_y + lanes.right_fit[2]+lanes.left_fit[0] * line_y * line_y + lanes.left_fit[1]* line_y + lanes.left_fit[2])/2; cout<<center_x<<endl; } line_error = center_x - 160; //line_error=100; cout << left_x << "," << right_x << "," << center_x << "," << line_error << endl; visualize(white_image, lanes); //namedWindow("img", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 //resizeWindow("img", 320, 240); // 设置窗口尺寸 //moveWindow("img", 320, 50); // 设置窗口位置 //imshow("img", img_clone); namedWindow("combined_image", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 resizeWindow("combined_image", 320, 240); // 设置窗口尺寸 moveWindow("combined_image", 640, 50); // 设置窗口位置 imshow("combined_image", img_combined); namedWindow("white_image", cv::WINDOW_NORMAL); // 创建可调整大小的窗口 resizeWindow("white_image", 320, 240); // 设置窗口尺寸 moveWindow("white_image", 960, 50); // 设置窗口位置 imshow("white_image", white_image); //Start_motor(); } */ if (cv::waitKey(1) == 27)break; //if(car_blake_flag == 1) ;//break;//结束代码 } gpioTerminate(); capture.release(); // 释放摄像头 destroyAllWindows(); // 关闭所有窗口 //uart_close(GPS); return 0; }Mat per_wt(Mat& frame) { int img_h, img_w; img_clone = frame.clone(); img_h = img_clone.rows; // 图像高度 img_w = img_clone.cols; vector<cv::Point2f> src = { Point2f(125, 198), Point2f(213, 198), Point2f(295, 237), Point2f(55, 237) }; vector<cv::Point2f> dst = { Point2f(100,0), Point2f(img_w - 100, 0), Point2f(img_w - 100, img_h), Point2f(100, img_h) }; // 定义目标坐标(变换后的四个点) vector<cv::Point> polygon; for (const auto& pt : src) { polygon.push_back(Point(static_cast<int>(pt.x), static_cast<int>(pt.y))); } polylines(img_clone, polygon, 1, Scalar(0, 0, 255), 3, cv::LINE_AA); //for (size_t i = 0; i < src.size(); ++i) //{ // circle(img, cv::Point(static_cast<int>(src[i].x), static_cast<int>(src[i].y)), 5, cv::Scalar(0, 0, 255), -1); //} // 计算透视变换矩阵 Mat M = getPerspectiveTransform(src, dst); Mat Minv = getPerspectiveTransform(dst, src); // 应用透视 warpPerspective(frame, warped, M, cv::Size(img_w, img_h), cv::INTER_LINEAR); waitKey(5); return warped; }void crossroad(void)//斑马线识别 { Mat blur; while(1) { GaussianBlur(img, blur, Size(5, 5), 0); Mat hsv; cvtColor(blur, hsv, COLOR_BGR2HSV); Scalar lower_white = Scalar(0, 0, 200); Scalar upper_white = Scalar(180, 40, 255); Mat cross_mask; inRange(hsv, lower_white, upper_white, cross_mask); // Mat edges; // Canny(blur, edges, 50, 150); // bitwise_or(cross_mask, edges, cross_mask); Mat kernel = getStructuringElement(MORPH_RECT, Size(7, 7)); //dilate(mask1, mask1, kernel); //erode(mask1, mask1, kernel); morphologyEx(cross_mask, cross_mask, MORPH_CLOSE, kernel); Rect roi(0,240,640,240); Mat region = cross_mask(roi); imshow("combined_image", region); //imshow("combined_image", mask1_roi); int stripe_count = 0, transitions = 0; for (int i = 0; i < region.rows; i++) { transitions = 0; for (int j = 5; j < region.cols - 5; j++) { if (region.at<uchar>(i, j) != region.at<uchar>(i, j - 1)) transitions++; } //cout<<"transitions:"<<transitions<<endl; if (transitions >= 6) stripe_count++; } cross_flag = (stripe_count >= 20) ? 1 : 0; cout << "stripe_count"<<stripe_count<<"cross_flag:" << cross_flag << endl; if(cross_flag==1){Control_stop();audio();break;} waitKey(5); } }
11-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值