c++版本的opencv检测PCB上的灯珠(颜色)

   不多废话,直接上代码:

#include "read.hpp"
#include 

#include 

//圆形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> contours;
    std::vector hierarchy;

    cv::findContours(resize_img,contours,hierarchy,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE);
    std::cout << contours.size() << std::endl;

    //计算面积contourArea
    std::vector 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::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 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 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 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 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> contours;
    std::vector 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 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 
#include 
#include 
#include 
#include 
#include 
#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 
#include 
#include 
#include 
#include 
#include "json/json.h"
#include 
#include 
#include 
#include 
#include 

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配置文件内容:

{
    "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 的部分需自行加载进来。谢谢~ 

你可能感兴趣的:(c++,opencv,开发语言)