【OpenCV】颜色识别实例(瓶盖)

HSV颜色分区参考: 

【OpenCV】HSV颜色识别-HSV基本颜色分量范围

#include <cv.h>
#include <highgui.h>
#include <vector>
using namespace std;
#define MINAREA 600


int main()
{
    IplImage* srcRGB =  cvLoadImage("33333.bmp");
	IplImage* src= cvCreateImage(cvGetSize(srcRGB), 8, 1);	

	cvCvtColor(srcRGB, src,CV_RGB2GRAY);
	cvNamedWindow("srcRGB", 0);
	if(srcRGB!=NULL)
	{
		cvShowImage("srcRGB",srcRGB);
	}
	
	/**********************************转HSV分离通道**********************************/
	IplImage* hsv = cvCreateImage(cvGetSize(srcRGB), 8, 3);
	cvCvtColor( srcRGB, hsv, CV_BGR2HSV );

	IplImage* img_h = cvCreateImage(cvGetSize(src), 8, 1);
	IplImage* img_s = cvCreateImage(cvGetSize(src), 8, 1);
	IplImage* img_v = cvCreateImage(cvGetSize(src), 8, 1);

	cvSplit(hsv, img_h, img_s, img_v, NULL);
	
	cvNamedWindow("img_h", 0);
	cvShowImage("img_h", img_h);
	cvNamedWindow("img_s", 0);
	cvShowImage("img_s", img_s);
	cvNamedWindow("img_v", 0);
	cvShowImage("img_v", img_v);

	cvNamedWindow("Thresh", 0);
	
	IplImage* Thresh_img2 = cvCreateImage(cvGetSize(src), 8, 1);
	IplImage* Thresh_img1 = cvCreateImage(cvGetSize(src), 8, 1);
	IplImage* Thresh_img = cvCreateImage(cvGetSize(src), 8, 1);

	cvThreshold(img_s, Thresh_img1, 90, 255, CV_THRESH_BINARY);
	cvErode( Thresh_img1, Thresh_img1, NULL, 2 );
	cvDilate(Thresh_img1, Thresh_img1, NULL, 2);

	cvNamedWindow("img_ED", 0);
	cvShowImage("img_ED", Thresh_img1);

	cvShowImage("Thresh", Thresh_img1);
	cvWaitKey(0);
	cvThreshold(img_v, Thresh_img2, 248, 255, CV_THRESH_BINARY);
	cvAdd(Thresh_img1,Thresh_img2, Thresh_img);
	
	cvNamedWindow("img_ADD", 0);
	cvShowImage("img_ADD", Thresh_img);

	/***********************************提取目标*************************************/
	IplImage* temp = cvCreateImage(cvGetSize(src), 8, 1);
	IplImage* dst = cvCreateImage(cvGetSize(src), 8, 1);
	IplImage* dstRGB = cvCreateImage(cvGetSize(src), 8, 3);
	cvZero(dstRGB);
	cvZero(temp);
	cvZero(dst);

	CvMemStorage* storage = cvCreateMemStorage(0);  
    CvSeq* contour = 0;
	
	CvPoint center[20] = {cvPoint(0,0)};
	
    int contour_num = cvFindContours(Thresh_img1, storage, &contour, sizeof(CvContour), 
	   CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 
	
	for(int i = 0; contour != 0; contour = contour->h_next, i++ )    
    {  
        double length = cvArcLength(contour);  
        if(length < MINAREA)     
        {
           cvSeqRemove(contour, 0);           // 删除面积小于设定值的轮廓  
           continue;
        }  
		int count = 0;
		if(length >= MINAREA)
		{
		 count++;
	     cvDrawContours(temp, contour, cvScalar(255,255,255), cvScalar(255,255,255), -1,CV_FILLED); //作为掩码		                     
		 cvCopy(img_h, dst, temp);
		// cvSeqRemove(contour->h_prev, 0); 
		
		 ///目标区域hue通道的平均灰度值
		 int pix_count=0;
		 int  gray_value = 0;
		 for(int x=0; x<dst->height; x++)
		 {
			 uchar* ptr = (uchar*) dst->imageData+x*dst->widthStep;
			 for(int y=0; y<dst->width; y++)
			 {				
				if(ptr[y])
					{
						gray_value += ptr[y];
						pix_count++;
				    }
			 }
		 }
		 gray_value/=pix_count;

         /找目标中心//
		
		 CvSeqReader reader;
		 CvPoint pt = cvPoint(0,0);
		 cvStartReadSeq(contour, &reader);
		 
		 int point_count = 0;

		 for(int i=0; i<contour->total; i++)
			{				
				CV_READ_SEQ_ELEM(pt, reader);
				center[count].x+=pt.x;
				center[count].y+=pt.y;
				point_count++;
		    }
		
		 center[count].x=center[count].x/point_count;     //中心坐标
		 center[count].y=center[count].y/point_count;
		 cout<<"X:"<<center[count].x << " Y:" << center[count].y<<endl;
	    		 
		 /
		 cvCopy(srcRGB, dstRGB, temp);		
		// char* Gray_Value = "hello";
		// itoa(gray_value, Gray_Value , 20);
		// sprintf(Gray_Value,"%d",gray_value);
		// cout<<Gray_Value<<endl;
		// CvFont font;
	    // cvInitFont(&font, CV_FONT_HERSHEY_DUPLEX, 0.8f, 0.8f, 1, 1);
		// cvPutText(dstRGB,  Gray_Value, center,	&font, CV_RGB(255,255,255) );
		 cvCircle(dstRGB, center[count], 6, CV_RGB(0,255,0), 2);
		 cout<<gray_value<<endl;
		 cvNamedWindow("dstRGB", 0);
		 cvShowImage("dstRGB", dstRGB);	    
		}
		//cvWaitKey(0);
	} 
	cvWaitKey(0);   
			
	cvReleaseImage(&img_h);
	cvReleaseImage(&img_s);
	cvReleaseImage(&img_v);	
	cvReleaseImage(&hsv);
	cvReleaseImage(&src);
	cvDestroyAllWindows();
} 

#include "stdafx.h"

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

double GetP2PDis(Point2d p1, Point2d p2);
int FuncCountHSV(Mat mat);

int _tmain(int argc, _TCHAR* argv[])
{
	Mat img = imread("01.bmp");
	Mat imgSrc;
	img.copyTo(imgSrc);

	double time0 = static_cast<double>(getTickCount());    //起始时间

	const Size size = img.size();
	int height = size.height;
	int width = size.width;

	//---To HSV---//
	Mat hsv = Mat::zeros(height, width, CV_8UC3);
	cvtColor(imgSrc, hsv, CV_RGB2HSV);

	//---分离通道---//
	vector<cv::Mat> mv;
	Mat hsv_h = Mat::zeros(height, width, CV_8UC1);
	Mat hsv_s = Mat::zeros(height, width, CV_8UC1);
	Mat hsv_v = Mat::zeros(height, width, CV_8UC1);

	split(hsv, mv);
	hsv_h = mv.at(0);
	hsv_s = mv.at(1);
	hsv_v = mv.at(2);

	//---S-处理---//
	Mat matS1 = Mat::zeros(height, width, CV_8UC1);
	Mat matS2 = Mat::zeros(height, width, CV_8UC1);
	Mat matS3 = Mat::zeros(height, width, CV_8UC1);
	Mat element_Se = getStructuringElement(MORPH_ELLIPSE,Size(5,5));
	Mat element_Sd = getStructuringElement(MORPH_ELLIPSE,Size(5,5));
	threshold(hsv_s, matS1, 90, 255, CV_THRESH_BINARY);
	erode( matS1, matS2, element_Se);
	dilate(matS2, matS3, element_Sd);

	//---V-处理---//
	Mat matV1 = Mat::zeros(height, width, CV_8UC1);
	threshold(hsv_v, matV1, 248, 255, CV_THRESH_BINARY);

	//---叠加----//
	Mat matAdd = Mat::zeros(height, width, CV_8UC1);
	add(matS3, matV1, matAdd);

	Mat imgDst = matAdd;
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;

	findContours(imgDst, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0,0));  

	size_t nContoursNum = contours.size();  
	cout << "轮廓数量:" << nContoursNum << endl;

	namedWindow("Test1", 0);
	resizeWindow("Test1", 300, 200);

	size_t RstNum = 0;
	for ( size_t index = 0; index < nContoursNum; index++ )
	{
		size_t nPerSum = contours[index].size();
		double dPerimeter = 0.0;  // 轮廓周长

		for ( size_t i=0; i < nPerSum; i++ )
		{
			//----计算周长----//
			double dCurDis = 0.0;
			if ( i < nPerSum - 1)
			{
				dCurDis = GetP2PDis(contours[index].at(i), contours[index].at(i+1) );
			}
			else
			{
				dCurDis = GetP2PDis(contours[index].at(i), contours[index].at(0) );
			}
			dPerimeter += dCurDis;
		}
		
		if ( dPerimeter > 600 )
		{
			RstNum++;
			//-----计算中心坐标-----//
			int nMinX = contours[index].at(0).x;
			int nMinY = contours[index].at(0).y;
			int nMaxX = contours[index].at(0).x;
			int nMaxY = contours[index].at(0).y;

			double dSumH = 0.0;
			for (size_t i = 1; i < nPerSum; i++ )
			{
				if ( contours[index].at(i).x > nMaxX ) nMaxX = contours[index].at(i).x;
				if ( contours[index].at(i).y > nMaxY ) nMaxY = contours[index].at(i).y;
				if ( contours[index].at(i).x < nMinX ) nMinX = contours[index].at(i).x;
				if ( contours[index].at(i).y < nMinY ) nMinY = contours[index].at(i).y;

				//dSumH += imgSrc.ptr<uchar>(contours[index].at(i).y)[contours[index].at(i).x];
			}

			Point center;
			center.x = nMinX + (nMaxX - nMinX) / 2;
			center.y = nMinY + (nMaxY - nMinY) / 2;
			cout << "Num: " << RstNum << " Points" << nPerSum << " Length:" << dPerimeter << "----X:" << center.x << " Y:" << center.y<< endl;
			
			//------统计颜色-----//
			int colWidth  = (nMaxX - nMinX);
			int colHeight = (nMaxY - nMinY);
			
			Mat matColorH = Mat::zeros(colWidth, colHeight, CV_8UC1);
			Mat matColorS = Mat::zeros(colWidth, colHeight, CV_8UC1);
			Mat matColorV = Mat::zeros(colWidth, colHeight, CV_8UC1);

			Rect rectROI( nMinX, nMinY, colWidth, colHeight );
			hsv_h(rectROI).convertTo(matColorH, matColorH.type(), 1, 0);
			hsv_s(rectROI).convertTo(matColorS, matColorS.type(), 1, 0);
			hsv_v(rectROI).convertTo(matColorV, matColorV.type(), 1, 0);


			Scalar mean_h = mean(matColorH);
			Scalar mean_s = mean(matColorS);
			Scalar mean_v = mean(matColorV);
			double dH = mean_h[0];
			double dS = mean_s[0];
			double dV = mean_v[0];

			cout << "H:" << dH << " S:" << dS  << " V:" << dV;
			
// 			if ( dH>0 && dH<180 && dS>0 && dS<255 && dV>0 && dV<46 ) cout << "01黑色 ";
// 			if ( dH>0 && dH<180 && dS>0 && dS<43 && dV>46 && dV<220 ) cout << "02灰色 ";
// 			if ( dH>0 && dH<180 && dS>0 && dS<30 && dV>221 && dV<255 ) cout << "03白色 ";
// 			if ( dH>0 && dH<10 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "04红色 ";
// 			if ( dH>156 && dH<180 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "04红色2 ";
// 			if ( dH>11 && dH<25 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "05橙色 ";
// 			if ( dH>26 && dH<34 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "06黄色 ";
// 			if ( dH>35 && dH<77 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "07绿色 ";
// 			if ( dH>78 && dH<99 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "08青色 ";
// 			if ( dH>100 && dH<124 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "09蓝色 ";
// 			if ( dH>125 && dH<155 && dS>43 && dS<255 && dV>46 && dV<255 ) cout << "10紫色 ";
			if ( dH>0 && dH<180 )
			{
				if ( dH>0 && dH<=10 ) cout << "04红色 ";
				if ( dH>10 && dH<=25 ) cout << "05橙色 ";
				if ( dH>25 && dH<=34 ) cout << "06黄色 ";
				if ( dH>34 && dH<=77 ) cout << "07绿色 ";
				if ( dH>77 && dH<=99 ) cout << "08青色 ";
				if ( dH>99 && dH<=124 ) cout << "09蓝色 ";
				if ( dH>124 && dH<=155 ) cout << "10紫色 ";
				if ( dH>155 && dH<=180 ) cout << "04红色2 ";

				if ( dH>0 && dH<180 && dS>0 && dS<255 && dV>0 && dV<46 ) cout << "01黑色 ";
				if ( dH>0 && dH<180 && dS>0 && dS<43 && dV>46 && dV<220 ) cout << "02灰色 ";
				if ( dH>0 && dH<180 && dS>0 && dS<43 && dV>221 && dV<255 ) cout << "03白色 ";
			}
			cout << endl;
			cout << endl;

			imshow("Test1", matColorH);
			waitKey();
// 			imshow("Test1", matColorS);
// 			waitKey();
// 			imshow("Test1", matColorV);
// 			waitKey();

			
			//----绘制结果轮廓----//
			Scalar color( rand()&255, rand()&255, rand()&255 );
			drawContours( imgSrc, contours, index, color, 10, 8, hierarchy );
			circle(imgSrc, center, 5 , color, 5, 8, 0); 

			char str_i[10];
			sprintf(str_i,"%d",RstNum);
			putText(imgSrc, str_i, center, CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0,255,0), 2, 8);
			imwrite("result.bmp", imgSrc);
		}
	}
	time0 = ((double)getTickCount() - time0) / getTickFrequency();    //运行后时间
	cout << "Run time : " << time0 << endl;

 	
// 	imshow("Test1", hsv);
// 	waitKey();
// 
// 	imshow("Test1", hsv_h);
// 	waitKey();
// 	imshow("Test1", hsv_s);
// 	waitKey();
// 	imshow("Test1", hsv_v);
// 	waitKey();
// 
// 	imshow("Test1", matS1);
// 	waitKey();
// 	imshow("Test1", matS2);
// 	waitKey();
// 	imshow("Test1", matS3);
// 	waitKey();
// 
// 	imshow("Test1", matV1);
// 	waitKey();
// 	imshow("Test1", matV2);
// 	waitKey();
// 	imshow("Test1", matV3);
// 	waitKey();
// 
// 	imshow("Test1", matAdd);
// 	waitKey();

// 	imshow("Test1", imgDst);
// 	waitKey();
	imshow("Test1", imgSrc);
	waitKey();

	return 0;
}

double GetP2PDis(Point2d p1, Point2d p2)
{
	double dDis = 0.0;
	dDis = sqrt((p2.x-p1.x)*(p2.x-p1.x) + (p2.y-p1.y)*(p2.y-p1.y));
	return dDis;
}


//----------------------------------------------
            Camera.Size size = mCamera.getParameters().getPreviewSize();
            final int w = size.width;
            final int h = size.height;
            final YuvImage image = new YuvImage(mData, ImageFormat.NV21, w, h, null);
            ByteArrayOutputStream os = new ByteArrayOutputStream(mData.length);
            if (!image.compressToJpeg(new Rect(0, 0, w, h), 100, os)) {
                return;
            }
            byte[] tmp = os.toByteArray();
            Bitmap bitmap = BitmapFactory.decodeByteArray(tmp, 0, tmp.length);
            Bitmap input = rotateBitmap(bitmap, 90);
            Bitmap bmp = input.copy(Bitmap.Config.ARGB_8888, true);

            int nw = bmp.getWidth();
            int nh = bmp.getHeight();
            int[] pix = new int[nw * nh];
            bmp.getPixels(pix, 0, nw, 0, 0, nw, nh);
            int[] resultPixels = OpenCVHelper.colorDetection(pix, nw, nh);
            Bitmap result = Bitmap.createBitmap(nw, nh, Bitmap.Config.RGB_565);
            result.setPixels(resultPixels,0,nw,0,0,nw,h);
            image_show.setImageBitmap(result);



JNIEXPORT jintArray JNICALL Java_com_example_targetlocationapp_OpenCVHelper_colorDetection
  (JNIEnv *env, jclass obj, jintArray  buf, jint w, jint h){
    jint *cbuf;
    cbuf = env->GetIntArrayElements(buf,JNI_FALSE);
    if (NULL == cbuf)
    {
        return 0;
    }

    Mat srcImage(h,w,CV_8UC4,(unsigned char*) cbuf);
    Mat rgbImage;
    cvtColor(srcImage, rgbImage, COLOR_BGRA2RGB);

    for (size_t i = 0; i < 5; i++)
    {
        Point center(100 + 50*i, 150 + 30*i);
        ellipse(rgbImage, center, Size(100, 150), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0);
    }

    int size = w * h;
    jintArray result = env->NewIntArray(size);
    //jint *pArrayBuf = env->GetIntArrayElements(result, nullptr);
    u_char *ptr = rgbImage.ptr(0);
    u_char *ptrRst = srcImage.ptr(0);
    for(int i=0;i < size; i++){
        // int grayScale = (int)(ptr[3*i+2]*0.299 + ptr[3*i+1]*0.587 + ptr[3*i+0]*0.144 );
        // pArrayBuf[i] = (int)ptr[3*i+2];
        ptrRst[4*i+0] = (int)ptr[3*i+2];
        ptrRst[4*i+1] = (int)ptr[3*i+1];
        ptrRst[4*i+2] = (int)ptr[3*i+0];
    }
    env->SetIntArrayRegion(result,0,size,cbuf);
    env->ReleaseIntArrayElements(buf,cbuf,0);
    return result;
}


JNIEXPORT jintArray JNICALL Java_com_example_app_OpenCVHelper_colorDet
        (JNIEnv *env, jclass obj, jbyteArray  yuv, jint w, jint h){
    jbyte * pBuf = (jbyte*)env->GetByteArrayElements(yuv, 0);
    int width = w;
    int height = h + h /2;
    cv::Mat imageSrc(height, width , CV_8UC1, (unsigned char*)pBuf );

    cv::Mat imageBGR;
    cv::cvtColor(imageSrc, imageBGR, CV_YUV2BGR_NV21); //将YUV转换成BGR

    cv::Mat srcSize;
    cv::resize(imageBGR, srcSize, Size(h/20, w/20));

    cv::Mat timage;
    cv::transpose(imageBGR, timage);  //图像转置
    cv::Mat yimage;
    cv::flip(timage, yimage, 1);   //Y方向镜像

    //---------图像处理---------
    cv::Mat image(yimage);
    cv::Mat frameHSV;
    cv::medianBlur(image, image, 5);
    cv::cvtColor(image, frameHSV, CV_BGR2HSV);

    cv::Mat dstTemp1(image.rows, image.cols, CV_8UC1);
    cv::Mat dstTemp2(image.rows, image.cols, CV_8UC1);
    cv::inRange(frameHSV, Scalar(0,30,30), Scalar(40,170,256), dstTemp1);
    cv::inRange(frameHSV, Scalar(156, 30, 30), Scalar(180, 170, 256), dstTemp2);

    cv::Mat mask(image.rows, image.cols, CV_8UC1);  // 2值掩膜
    cv::add(dstTemp1, dstTemp2, mask);

    // 形态学操作,去除噪声,并使手的边界更加清晰
    cv::Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    cv::erode(mask, mask, element);
    cv::morphologyEx(mask, mask, MORPH_OPEN, element);
    cv::dilate(mask, mask, element);
    cv::morphologyEx(mask, mask, MORPH_CLOSE, element);

    cv::vector<cv::vector<cv::Point>> contours;	// 轮廓
    cv::vector<cv::Vec4i> hierarchy;	// 轮廓的结构信息
    cv::vector<cv::vector<cv::Point>> filterContours;	// 筛选后的轮廓

    contours.clear();
    hierarchy.clear();
    filterContours.clear();

    Mat maskDst = mask;
    // 得到手的轮廓
    //CV_RETR_EXTERNAL 只检测出最外轮廓即c0。图2中第一个轮廓指向最外的序列,除此之外没有别的连接。
    //CV_RETR_LIST 检测出所有的轮廓并将他们保存到表(list)中,图2中描绘了这个表,被找到的9条轮廓相互之间由h_prev和h_next连接。
    //CV_RETR_COMP 检测出所有的轮廓并将他们组织成双层的结构,第一层是外部轮廓边界,第二层边界是孔的边界。
    //CV_RETR_TREE 检测出所有轮廓并且重新建立网状的轮廓结构。
    cv::findContours(mask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    size_t nContoursNum = contours.size();
    size_t nCountNum = 0;

    // 去除伪轮廓
    cv::Mat dst(image.rows, image.cols, CV_8UC3);
    for (size_t i = 0; i < contours.size(); i++)
    {
        cv::Scalar color(rand() & 255, rand() & 255, rand() & 255);
        cv::drawContours(dst, contours, i, color, CV_FILLED, 8, hierarchy);
    }

    cv::Mat dstSize;
    cv::resize(dst, dstSize, Size(h, w));

    const int size = w * h;
    jintArray result = env->NewIntArray(size);
    jint* pArrayBuf = env->GetIntArrayElements(result, nullptr);
    Mat dstShow(h, w, CV_8UC4, (unsigned char* )pArrayBuf);
    u_char* ptr = dstSize.ptr(0);
    u_char* ptrRst = dstShow.ptr(0);
    for(int i=0;i<size;i++){
        memcpy(ptrRst+4*i+0, ptr+3*i+0, sizeof(u_char));
        memcpy(ptrRst+4*i+1, ptr+3*i+1, sizeof(u_char));
        memcpy(ptrRst+4*i+2, ptr+3*i+2, sizeof(u_char));
    }
    env->SetIntArrayRegion(result, 0, size, pArrayBuf);
    env->ReleaseIntArrayElements(result, pArrayBuf, 0);
    env->ReleaseByteArrayElements(yuv, pBuf, 0);
    return result;
}

  • 13
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值