opencv(C++) 学习记录11.30(颜色识别)


2019-11-30     

这周主要还是在学习opencv基本API的应用与原理,同时也在学习C++的线程,那么这次就记录对灯条的颜色识别 

  HSV基本颜色分量范围(通过实验得到的模糊范围,实际操作中我们可以据此做出适当调整)      

 

 

 

                                                                                      

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>
#include <math.h>
using namespace cv;
using namespace std;

int main()
{
//VideoCapture cap("D:/H.mp4"); //capture the video from web cam

//if (!cap.isOpened()) // if not success, exit program
//{
// cout << "Cannot open the web cam" << endl;
// return -1;
//}

namedWindow("control", 1);
int ctrl = 0;
createTrackbar("ctrl", "control", &ctrl, 7);

while (true)
{
Mat imgOriginal;

//bool bSuccess = cap.read(imgOriginal); 
//if (!bSuccess) 
//{
// cout << "Cannot read a frame from video stream" << endl;
// break;
//}

imgOriginal = imread("D:/L.png");

Mat imgHSV, imgBGR;
Mat imgThresholded;

if (0)
{
vector<Mat> hsvSplit; //创建向量容器,存放HSV的三通道数据
cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV
split(imgHSV, hsvSplit); //分类原图像的HSV三通道
equalizeHist(hsvSplit[2], hsvSplit[2]); //对HSV的亮度通道进行直方图均衡
merge(hsvSplit, imgHSV);//合并三种通道
cvtColor(imgHSV, imgBGR, COLOR_HSV2BGR); //将HSV空间转回至RGB空间,为接下来的颜色识别做准备
}
else
{
imgBGR = imgOriginal.clone();
}

 

switch (ctrl)
{
case 0:
{
inRange(imgBGR, Scalar(60, 120, 245), Scalar(120, 255, 255), imgThresholded); //蓝色
break;
}
case 1:
{
inRange(imgBGR, Scalar(128, 128, 128), Scalar(255, 255, 255), imgThresholded); //白色
break;
}
case 2:
{
inRange(imgBGR, Scalar(128, 128, 0), Scalar(255, 255, 127), imgThresholded); //靛色
break;
}
case 3:
{
inRange(imgBGR, Scalar(128, 0, 128), Scalar(255, 127, 255), imgThresholded); //紫色
break;
}
case 4:
{
inRange(imgBGR, Scalar(0, 128, 128), Scalar(127, 255, 255), imgThresholded); //黄色
break;
}
case 5:
{
inRange(imgBGR, Scalar(0, 128, 0), Scalar(127, 255, 127), imgThresholded); //绿色
break;
}
case 6:
{
inRange(imgBGR, Scalar(0, 0, 128), Scalar(127, 127, 255), imgThresholded); //红色
break;
}
case 7:
{
inRange(imgBGR, Scalar(0, 0, 0), Scalar(127, 127, 127), imgThresholded); //黑色
break;
}
}

imshow("形态学去噪声前", imgThresholded);

Mat element = getStructuringElement(MORPH_RECT, Size(10, 15));
morphologyEx(imgThresholded, imgThresholded, MORPH_OPEN, element);
morphologyEx(imgThresholded, imgThresholded, MORPH_CLOSE, element);

imshow("Thresholded Image", imgThresholded); //show the thresholded image
imshow("直方图均衡以后", imgBGR);
imshow("Original", imgOriginal); //show the original image

char key = (char)waitKey(300);
if (key == 27)
break;
}

return 0;

}

                       

 

 

通过滑条发现ctrl=1 时 效果较好,但数字没有消除。

当我单独分出蓝色识别范围,并继续用HSV空间时。

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>
#include <math.h>
using namespace cv;
using namespace std;

int main()
{
    //VideoCapture cap("D:/H.mp4"); //if (!cap.isOpened()) //{
    //    cout << "Cannot open the web cam" << endl;
    //    return -1;
    //}

    namedWindow("control", 1);
    int ctrl = 0;
    createTrackbar("ctrl", "control", &ctrl, 7);

    while (true)
    {
        Mat imgOriginal;

        //bool bSuccess = cap.read(imgOriginal); //if (!bSuccess) //if not success, break loop
        //{
        //    cout << "Cannot read a frame from video stream" << endl;
        //    break;
        //}

        imgOriginal = imread("D:/L.png");

        Mat imgHSV, imgBGR;
        Mat imgThresholded;

        if (imgOriginal.empty())
        {
            cout << "open failed" << endl;
            return -1;
        }
        /*else
        {
            imgBGR = imgOriginal.clone();
        }
*/
            vector<Mat> hsvSplit; //创建向量容器,存放HSV的三通道数据
            cvtColor(imgOriginal, imgHSV, COLOR_BGR2HSV); 
            split(imgHSV, hsvSplit);    //分类原图像的HSV三通道
            equalizeHist(hsvSplit[2], hsvSplit[2]); //对HSV的亮度通道进行直方图均衡
            merge(hsvSplit, imgBGR);//合并三种通道
            //cvtColor(imgHSV, imgBGR, COLOR_HSV2BGR); //将HSV空间转回至RGB空间,为接下来的颜色识别做准备

        switch (ctrl)
        {
        case 0:
        {
            inRange(imgBGR, Scalar(60, 120, 245), Scalar(120, 255, 255), imgThresholded); //蓝色
            break;
        }
        case 1:
        {
            inRange(imgBGR, Scalar(128, 128, 128), Scalar(255, 255, 255), imgThresholded); //白色
            break;
        }
        case 2:
        {
            inRange(imgBGR, Scalar(128, 128, 0), Scalar(255, 255, 127), imgThresholded); //靛色
            break;
        }
        case 3:
        {
            inRange(imgBGR, Scalar(128, 0, 128), Scalar(255, 127, 255), imgThresholded); //紫色
            break;
        }
        case 4:
        {
            inRange(imgBGR, Scalar(0, 128, 128), Scalar(127, 255, 255), imgThresholded); //黄色
            break;
        }
        case 5:
        {
            inRange(imgBGR, Scalar(0, 128, 0), Scalar(127, 255, 127), imgThresholded); //绿色
            break;
        }
        case 6:
        {
            inRange(imgBGR, Scalar(0, 0, 128), Scalar(127, 127, 255), imgThresholded); //红色
            break;
        }
        case 7:
        {
            inRange(imgBGR, Scalar(0, 0, 0), Scalar(127, 127, 127), imgThresholded); //黑色
            break;
        }
        }

        imshow("形态学去噪声前", imgThresholded);

        Mat element = getStructuringElement(MORPH_RECT, Size(10, 15));
        morphologyEx(imgThresholded, imgThresholded, MORPH_OPEN, element);
        morphologyEx(imgThresholded, imgThresholded, MORPH_CLOSE, element);

        imshow("Thresholded Image", imgThresholded); //show the thresholded image
        imshow("直方图均衡以后", imgBGR);
        imshow("Original", imgOriginal); //show the original image

        char key = (char)waitKey(300);
        if (key == 27)
            break;
    }

    return 0;

}

 

 效果如下

 

 

 

通过代码对比发现如果将HSV再转换位BGR空间的时候,HSV的颜色将不适用,因此做好图像的预处理是非常重要。这对于图像转换为视频有着必然的联系。

总结一下部分API功能及代码讲解。

 

 

 

 

InRange
检查数组元素是否在两个数组之间
void cvInRange( const CvArr* src, const CvArr* lower, const CvArr* upper, CvArr*
dst );
src
第一个原数组
lower
包括进的下边界数组
upper
不包括进的上边界线数组
dst
输出数组必须是 8u 或 8s 类型.
函数 cvInRange 对输入的数组作范围检查:
dst(I)=lower(I)0 <= src(I)0 < upper(I)0
对于单通道数组:
dst(I)=lower(I)0 <= src(I)0 < upper(I)0 &&
lower(I)1 <= src(I)1 < upper(I)1
对二通道数组,以此类推
如果 src(I) 在范围内 dst(I)被设置为 0xff (每一位都是 '1')否则置 0 。 除了输出
数组所有数组必须是相同的类型相同的大小(或 ROI 大小)。 
 
 
Split
分割多通道数组成几个单通道数组或者从数组中提取一个通道
void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,
CvArr* dst2, CvArr* dst3 );
#define cvCvtPixToPlane cvSplit
src
原数组.
dst0...dst3
目标通道
函数 cvSplit 分割多通道数组成分离的单通道数组 d。可获得两种操作模式 . 如果原
数组有 N 通道且前 N 输出数组非 NULL, 所有的通道都会被从原数组中提取,如果前 N
个通道只有一个通道非 NULL 函数只提取该指定通道,否则会产生一个错误,余下的通
道(超过前 N 个通道的以上的)必须被设置成 NULL,对于设置了 COI 的 IplImage 结使
用 cvCopy 也可以从图像中提取单通道。 

 

Merge
从几个单通道数组组合多通道数组或插入一个单通到数组
void cvMerge( const CvArr* src0, const CvArr* src1,
const CvArr* src2, const CvArr* src3, CvArr* dst );
#define cvCvtPlaneToPix cvMerge
src0... src3
输入的通道.
dst
输出数组.
函数 cvMerge 是前一个函数的反向操作。如果输出数组有 N 个通道并且前 N 个输入通道
非 NULL,就拷贝所有通道到输出数组,如果在前 N 个通道中只有一个单通道非 NULL ,
只拷贝这个通道到输出数组,否则 就会产生错误。除前 N 通道以外的余下的通道必须
置 NULL。对于设置了 COI 的 IplImage 结构使用 cvCopy 也可以实现向图像中插入一个
通道 。 

 总之这周学习的东西也有不少,但没有整理好,因为快考试也在忙着复习功课,时间上特别的紧。后面我将继续学习下装甲板的识别。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM