不多废话,直接上代码:
#include "read.hpp"
#include <math.h>
#include <algorithm>
//圆形PCB板,有led灯点亮时
int DetectImage::native_read_pic(cv::String path){
if(access(path.c_str(),F_OK)!=0){
f << "Open pic file failed!" << std::endl;
return -1;
}
f << "native_read_pic run... " << std::endl;
cv::namedWindow("camera", cv::WINDOW_AUTOSIZE);
cv::Mat img = cv::imread(path);
cv::Mat resize_img(img);
cv::resize(img, resize_img, cv::Size(img.cols/cameraInfo.scale, img.rows/cameraInfo.scale));//缩小大小
cv::Mat draw_img(resize_img);//拷贝一张,便于画出轮廓
cv::cvtColor(resize_img,resize_img,cv::COLOR_BGR2GRAY);//变成灰度
cv::GaussianBlur(resize_img,resize_img,cv::Size(11,11),0);//高斯变化
cv:threshold(resize_img,resize_img,cameraInfo.threshold_value, cameraInfo.maxval,cv::THRESH_BINARY);//二值化
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(resize_img,contours,hierarchy,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);
std::cout << contours.size() << std::endl;
//计算面积contourArea
std::vector<double> Area_all;
for (int i = 0; i < contours.size(); i++)
{
Area_all.push_back(cv::contourArea(contours[i]));
}
double sum = std::accumulate(std::begin(Area_all), std::end(Area_all), 0.0);
double mean = sum / Area_all.size(); //周长的均值
std::vector<double>::iterator biggest = std::max_element(Area_all.begin(), Area_all.end());
int find_index = -1;
if(*biggest > mean *5){//如果最大值>平均值*5的话
find_index = std::distance(Area_all.begin(), biggest);
char text_show[16]={0};
sprintf(text_show,"Numis:%d",find_index);
cv::putText(draw_img, text_show, cv::Point(20, 20), cv::FONT_HERSHEY_SIMPLEX, 0.9, cv::Scalar(255, 0, 0));
}
for (int i = 0; i < contours.size(); i++){
if(i != find_index){
cv::drawContours(draw_img,contours,i,cv::Scalar(0, 0, 255), 1,8,hierarchy);
}
}
cv::imshow("camera", draw_img);
cv::waitKey(0);
return contours.size();
}
// camera open
int DetectImage::camera_operationImage(unsigned char read_or_wirte,const char* path){ //>> 1920×1080 == 1080p
//打开一个默认的相机
cv::VideoCapture capture(cameraInfo.camera_id);
//检查是否成功打开
if (!capture.isOpened()){
f << "Open capture failed!" << cameraInfo.camera_id << std::endl;
return -1;
}
//设置摄像头的分辨率
capture.set(cv::CAP_PROP_FRAME_WIDTH, cameraInfo.width);
capture.set(cv::CAP_PROP_FRAME_HEIGHT, cameraInfo.height);
capture.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
//摄像头帧数
capture.set(cv::CAP_PROP_FPS, cameraInfo.fps);
static unsigned char save_number = 1;
while(1)
{
cv::Mat frame;
capture>>frame;
if(read_or_wirte == 0){
cv::imshow("camera",frame);
}
if(save_number && read_or_wirte){
if(path == NULL || strlen(path) == 0){
cv::imwrite(cameraInfo.save_pic_path,frame);
}else{
cv::imwrite(path,frame);
}
save_number--;
cv::imshow("camera",frame);
}
if(cv::waitKey(30)==27){
break;
}
if(save_number==0){
break;
}
}
return 0;
}
//读配置文件
int DetectImage::readjson(std::string json_path){
Json::Reader json_reader;
Json::Value json_value;
std::ifstream infile(json_path, std::ios::binary);
if(!infile.is_open())
{
f << "Open config file failed!" << std::endl;
return -1;
}
if(json_reader.parse(infile, json_value)){
std::string pic_path = json_value["SavePath"].asString();
std::string log_path = json_value["LogFile"].asString();
//...
cameraInfo.save_pic_path = pic_path;
cameraInfo.logs_path = log_path;
cameraInfo.camera_id = json_value["camera_id"].asInt(); // 读取字符串型参数
cameraInfo.threshold_value = json_value["threshold"].asInt();
cameraInfo.maxval = json_value["maxval"].asInt();
cameraInfo.width = json_value["width"].asInt();
cameraInfo.height = json_value["height"].asInt();
cameraInfo.fps = json_value["fps"].asInt();
cameraInfo.scale = json_value["scale"].asInt();
//add
cameraInfo.circles.is_find_circles = json_value["circles"]["is_find_circles"].asBool();
cameraInfo.circles.is_draw_circles_dist = json_value["circles"]["is_draw_circles_dist"].asBool();
cameraInfo.circles.minCircles_minRadius = json_value["circles"]["minCircles_minRadius"].asInt();
cameraInfo.circles.minCircles_maxRadius = json_value["circles"]["minCircles_maxRadius"].asInt();
cameraInfo.circles.maxCircles_minRadius = json_value["circles"]["maxCircles_minRadius"].asInt();
cameraInfo.circles.maxCircles_maxRadius = json_value["circles"]["maxCircles_maxRadius"].asInt();
//add 2
cameraInfo.colors.red_color_hmin = json_value["colors"]["red_color_hmin"].asInt();
cameraInfo.colors.red_color_hmax = json_value["colors"]["red_color_hmax"].asInt();
cameraInfo.colors.green_color_hmin = json_value["colors"]["green_color_hmin"].asInt();
cameraInfo.colors.green_color_hmax = json_value["colors"]["green_color_hmax"].asInt();
cameraInfo.colors.blue_color_hmin = json_value["colors"]["blue_color_hmin"].asInt();
cameraInfo.colors.blue_color_hmax = json_value["colors"]["blue_color_hmax"].asInt();
cameraInfo.colors.color_smin = json_value["colors"]["color_smin"].asInt();
cameraInfo.colors.color_smax = json_value["colors"]["color_smax"].asInt();
}else{
init_default_camera();
}
infile.close();
return 0;
}
//设置默认参数
void DetectImage::init_default_camera(){
//set default settings
cameraInfo.camera_id = 0;
cameraInfo.scale = 1;
cameraInfo.threshold_value = 209;
cameraInfo.maxval = 255;
cameraInfo.width = 640;
cameraInfo.height = 480;
cameraInfo.fps = 60;
cameraInfo.logs_path = "./LogFile.txt";
cameraInfo.save_pic_path = "./Detect_image.jpeg";
//add
cameraInfo.circles = {false,false,5,15,100,120};
cameraInfo.colors = {0,10,35,77,100,124,43,255};
f << "use default_camera_params !" << std::endl;
}
int DetectImage::process(int argc, char* argv[]){
std::ofstream file_writer(cameraInfo.logs_path, std::ios_base::out);
//追加写入,在原来基础上加了ios::app
f.open(cameraInfo.logs_path,std::ios::out|std::ios::app);
//输入你想写入的内容
if(argc < 2){
f << "One argument expected"<< std::endl;
f.close();
return 0;
}
if(argc > 5){
f << "Too many arguments not supplied"<< std::endl;
f.close();
return 0;
}
int ret = 0;
if(strcmp(argv[1],"preview") == 0){
f << "preview process..."<< std::endl;
camera_operationImage(0,NULL);
}else if(strcmp(argv[1],"save") == 0){
camera_operationImage(1,argv[2]);
f << "save 1 process..."<< std::endl;
}else if(strcmp(argv[1],"detect") == 0){
f << "detect process..."<< std::endl;
int read_ret = 0;
if(argc >= 2){
if(argc >= 4){
if(strlen(argv[3]) > 0){
if(strcmp(argv[3],"circles") == 0){
ret = find_circles(argv[2]);
}else if(strcmp(argv[3],"colors") == 0){
ret = find_colors(argv[2],argv[4]);
}
return ret;
}
}
if(strlen(argv[2]) > 0){
f << "use cmd params path detect..."<< std::endl;
read_ret = native_read_pic(argv[2]);
}else{
f << "use config file path detect..."<< std::endl;
read_ret = native_read_pic(cameraInfo.save_pic_path);
}
}
char ret_str[32]={0};
sprintf(ret_str,"detect_completed:%d",read_ret);
f << ret_str << std::endl;
}
f << "normal exit"<< std::endl;
f.close();
return 0;
}
//得到2点之间的距离
float DetectImage::getDistance(cv::Point pointO, cv::Point pointA)
{
float distance;
distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
distance = sqrtf(distance);
return distance;
}
//找圆
int DetectImage::find_circles(cv::String path){
cv::namedWindow("find_circles", cv::WINDOW_AUTOSIZE);
if(access(path.c_str(),F_OK)!=0){
f << "Open pic file failed!" << std::endl;
return -1;
}
f << "find_circles run... " << std::endl;
if(!cameraInfo.circles.is_find_circles){
f << "not find_circles flag... " << std::endl;
return -2;
}
cv::Mat img = cv::imread(path);
cv::Mat resize_img(img);
cv::resize(img, resize_img, cv::Size(img.cols/cameraInfo.scale, img.rows/cameraInfo.scale));//缩小大小
cv::Mat draw_img(resize_img);
cv::cvtColor(resize_img,resize_img,cv::COLOR_BGR2GRAY);//变成灰度
//cv:threshold(resize_img,resize_img,cameraInfo.threshold_value, cameraInfo.maxval,cv::THRESH_BINARY);//二值化
cv::medianBlur(resize_img,resize_img,3);
//找小圆
std::vector<cv::Vec3f> circles;
cv::HoughCircles(resize_img,circles,cv::HOUGH_GRADIENT,1,10,100,30,cameraInfo.circles.minCircles_minRadius,cameraInfo.circles.minCircles_maxRadius);//should add config params
f << "circles_size :" << circles.size() << std::endl;
//找大圆
std::vector<cv::Vec3f> Maxcircles;
cv::HoughCircles(resize_img,Maxcircles,cv::HOUGH_GRADIENT,1,10,100,30,cameraInfo.circles.maxCircles_minRadius,cameraInfo.circles.maxCircles_maxRadius);//should add config params2
f << "Maxcircles_size :" << Maxcircles.size() << std::endl;
std::vector<double> max_dist_circle;
for (size_t i = 0; i < circles.size(); i++)
{
/* code */
cv::Vec3f circle = circles[i];
cv::circle(draw_img,cv::Point(circle[0],circle[1]),circle[2],cv::Scalar(0,255,0));//小圆
cv::circle(draw_img,cv::Point(circle[0],circle[1]),2,cv::Scalar(0,0,255));//小圆圆心
}
//如果找到的大圆数量大于2个,画出⚪
if(Maxcircles.size() > 2)
{
cv::Vec3f circle = Maxcircles[0];
cv::circle(draw_img,cv::Point(circle[0],circle[1]),circle[2],cv::Scalar(19,69,139));
//cv::circle(draw_img,cv::Point(circle[0],circle[1]),2,cv::Scalar(0,0,255));
}
max_dist_circle.push_back(0.0f);
for (size_t i = 1; i < circles.size(); i++){
cv::Vec3f o_circle = circles[0];//起始圆心
cv::Vec3f circle = circles[i];//其他圆心
double dist = getDistance(cv::Point(o_circle[0],o_circle[1]),cv::Point(circle[0],circle[1]));
max_dist_circle.push_back(dist);
//std::cout << dist << std::endl;
}
int max_pos = std::max_element(max_dist_circle.begin(), max_dist_circle.end())- max_dist_circle.begin();
f << "max pos:" << max_pos << std::endl;
//check range max_pos : 1 ~ size(max_dist_circle)
if(circles.size() > max_pos){
cv::Vec3f circles_LineA = circles[0];
cv::Vec3f circles_LineB = circles[max_pos];
//是否画出小圆间的 最大距离 直线
if(cameraInfo.circles.is_draw_circles_dist){
cv::line(draw_img,cv::Point(circles_LineA[0],circles_LineA[1]),cv::Point(circles_LineB[0],circles_LineB[1]),cv::Scalar(34,34,178));
}
}
cv::imshow("find_circles", draw_img);
cv::waitKey(0);
return 0;
}
/**
* @brief detectHSColor 提取图像中具有特定颜色范围的区域,图像是3 通道 BGR 图像
* @param image 输入图像,要求是 3 通道 BGR 图像
* @param minHue Hue 的最小值,Hue 范围 0-179 (Hue本质是个角度,在0-360之间,OpenCV 用 0-180 表示。0表示红色。)
* @param maxHue Hue 的最大值,Hue 范围 0-179
* @param minSat Sat 的最小值,Sat 范围 0-255
* @param maxSat Sat 的最大值,Sat 范围 0-255
* @param mask 提取出的区域
*/
void detectHSColor(const cv::Mat &image,
double minHue, double maxHue,
double minSat, double maxSat,
cv::Mat &mask)
{
cv::Mat hsv;
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
std::vector<cv::Mat> channels;
cv::split(hsv, channels);
cv::Mat mask1, mask2, hueMask;
cv::threshold(channels[0], mask1, maxHue, 255, cv::THRESH_BINARY_INV);
cv::threshold(channels[0], mask2, minHue, 255, cv::THRESH_BINARY);
if(minHue < maxHue)
{
hueMask = mask1 & mask2;
}
else
{
hueMask = mask1 | mask2;
}
cv::Mat satMask;
cv::inRange(channels[1], minSat, maxSat, satMask);
mask = hueMask & satMask;
}
//找颜色
int DetectImage::find_colors(cv::String path,char* argv){
cv::namedWindow("find_colors", cv::WINDOW_AUTOSIZE);
if(access(path.c_str(),F_OK)!=0){
f << "Open pic file failed!" << std::endl;
return -1;
}
if(argv == NULL) {
f << "plase input colors type!" << std::endl;
return -2;
}
f << "find_colors: " << argv << " , run... " << std::endl;
cv::Mat img = cv::imread(path);
cv::Mat resize_img(img);
if(cameraInfo.scale != 1){
cv::resize(img, resize_img, cv::Size(img.cols/cameraInfo.scale, img.rows/cameraInfo.scale));//缩小大小
}
cv::Mat draw_img(resize_img);
unsigned char h_min = 0;
unsigned char h_max = 0;
unsigned char s_min = cameraInfo.colors.color_smin;
unsigned char s_max = cameraInfo.colors.color_smax;
if(strcmp(argv,"red") == 0){
h_min = cameraInfo.colors.red_color_hmin;
h_max = cameraInfo.colors.red_color_hmax;
}else if(strcmp(argv,"green") == 0){
h_min = cameraInfo.colors.green_color_hmin;
h_max = cameraInfo.colors.green_color_hmax;
}else if(strcmp(argv,"blue") == 0){
h_min = cameraInfo.colors.blue_color_hmin;
h_max = cameraInfo.colors.blue_color_hmax;
}else{
return 0;
}
detectHSColor(resize_img,h_min,h_max,s_min,s_max,resize_img);
//找轮廓
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(resize_img,contours,hierarchy,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);
f << "find_colors_contours.size:" << contours.size() << std::endl;
//计算面积contourArea
std::vector<double> Area_all;
for (int i = 0; i < contours.size(); i++)
{
Area_all.push_back(cv::contourArea(contours[i]));
}
double sum = std::accumulate(std::begin(Area_all), std::end(Area_all), 0.0);
double mean = sum / Area_all.size(); //面积的均值
f << "find_colors_area,mean:" << mean << std::endl;
cv::imshow("find_colors", resize_img);
cv::waitKey(0);
return 0;
}
下面是main.cpp 的 部分:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <unistd.h>
#include <thread>
#include <string.h>
#include "read.hpp"
int main(int argc, char* argv[])
{
DetectImage detectImage;
detectImage.readjson("./Config.json");
detectImage.process(argc,argv);
return 0;
}
下面是 头文件
#ifndef __READ_HPP
#define __READ_HPP
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <unistd.h>
#include <numeric>
#include "json/json.h"
#include <fstream>
#include <fstream>
#include <read.hpp>
#include <thread>
#include <string.h>
typedef struct _Circles{
bool is_find_circles;
bool is_draw_circles_dist;
unsigned int minCircles_minRadius;
unsigned int minCircles_maxRadius;
unsigned int maxCircles_minRadius;
unsigned int maxCircles_maxRadius;
}Circles;
typedef struct _RGBColors{
unsigned char red_color_hmin;
unsigned char red_color_hmax;
unsigned char green_color_hmin;
unsigned char green_color_hmax;
unsigned char blue_color_hmin;
unsigned char blue_color_hmax;
unsigned char color_smin;
unsigned char color_smax;
}RGBColors;
typedef struct _CameraInfo {
unsigned char fps;
unsigned char camera_id;
unsigned int threshold_value;
unsigned int maxval;
unsigned int width;
unsigned int height;
unsigned int scale;
Circles circles;
RGBColors colors;
std::string save_pic_path;
std::string logs_path;
}CameraInfo;
class DetectImage
{
std::fstream f;
CameraInfo cameraInfo;
int camera_operationImage(unsigned char read_or_wirte,const char* path);
void init_default_camera();
int native_read_pic(cv::String path);
public:
int readjson(std::string json_path);
int process(int argc, char* argv[]);
//add
int find_circles(cv::String path);
int find_colors(cv::String path,char* argv);
float getDistance(cv::Point pointO, cv::Point pointA);//两点之间距离
};
#endif
附录 上 json配置文件内容:文章来源:https://www.toymoban.com/news/detail-524563.html
{
"camera_id":0,
"scale" :1,
"threshold":200,
"maxval" :255,
"width" :640,
"height" :480,
"fps" :60,
"SavePath":"./Detect_image.jpeg",
"LogFile":"./LogFile.txt",
"circles" :{
"is_find_circles":true,
"is_draw_circles_dist":false,
"minCircles_minRadius":25,
"minCircles_maxRadius":45,
"maxCircles_minRadius":300,
"maxCircles_maxRadius":560
},
"colors" :{
"red_color_hmin":0,
"red_color_hmax":10,
"green_color_hmin":35,
"green_color_hmax":77,
"blue_color_hmin":100,
"blue_color_hmax":124,
"color_smin":43,
"color_smax":255
}
}
jsoncpp 的部分需自行加载进来。谢谢~ 文章来源地址https://www.toymoban.com/news/detail-524563.html
到了这里,关于c++版本的opencv检测PCB上的灯珠(颜色)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!