基于OPENCV的树莓派按键自校正阈值的颜色识别
2019-09-25 本文已影响0人
CKHHAN
基于OPENCV的树莓派按键自校正阈值的颜色识别
前言:通过在选定区域内进行色彩的HSV参数识别,可利用按键进行自动的颜色识别的阈值选定,进而通过图形矩的计算得到目标图形的中心点坐标。
本人才疏学浅,还请多多指正,如有更好想法可通过邮箱hanckh@foxmail.com进行交流.
原理:
在OPENCV中图像的颜色识别一般是基于inRange()
函数进行目标阈值的限定,通过将图像转换为二值化图像,从而进行目标物体的识别和追踪。inRange()
函数中的参数是由HSV三个色彩参数决定,因此为了能自动的选定识别阈值,就必须要知道目标的色彩参数范围。通过对目标物体所处的ROI区域的HSV三层颜色直方图的分析,可得到当前目标的HSV参数,并通过人为选择的颜色拓展范围,再通过对该HSV参数进行记录,即可实现对目标的动态识别。
之后再通过目标物体二值化图像的边缘检测,对图像矩进行计算得到目标图像的中心点。
使用步骤
- 将识别物体放入ROI区域,在示例代码里表现为中心蓝点。
- 再按对应按键,进行参数的确认。
- 再按对应模式按键,进行识别模式的切换,进入动态识别模式
示例代码
/*
MIT License
Copyright (c) [2019] [HAN]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <wiringPi.h>
#include <wiringSerial.h>
using namespace cv;
using namespace std;
int H,S,V;
int max_value=0;
int flag=0,Step=1,affirm=0;
int fd;
Mat srcimageHSV;
class object
{
public:
int H,S,V;
Mat Mask;
Mat srcimageHSV;
Mat Origin_image;
void get_minmax(){
//*****人工设定HSV参数扩展范围******//
H_max=H+10;
S_max=S+75;
V_max=V+80;
H_min=H-10;
S_min=S-75;
V_min=V-80;
//********************************//
if(H_max>255){
H_max=255;
}
if(S_max>255){
S_max=255;
}
if(V_max>255){
V_max=255;
}
if(H_min<0){
H_min=0;
}
if(S_min<0){
S_min=0;
}
if(V_min<0){
V_min=0;
}
}
void tobe_threhold(){//进行二值化
inRange(srcimageHSV,Scalar(H_min,S_min,V_min),Scalar(H_max,S_max,V_max),Mask);
}
void show_image(){
imshow("Object_Mask",Mask);
}
void Get_TrackBar(){//回显识别出的HSV参数
namedWindow("Object", 1);
createTrackbar("H_min","Object",&H_min,255);
createTrackbar("S_min","Object",&S_min,255);
createTrackbar("V_min","Object",&V_min,255);
createTrackbar("H_max","Object",&H_max,255);
createTrackbar("S_max","Object",&S_max,255);
createTrackbar("V_max","Object",&V_max,255);
}
void calculate_Point(){//计算中心点
vector<vector<Point>> Object;
findContours(Mask,Object,CV_RETR_EXTERNAL,CV_RETR_TREE);
double maxArea = 0;//Find maxArea
vector<Point> maxContours;
for(uint i = 0 ; i < Object.size(); i++){
double area = contourArea(Object[i]);
if(area > maxArea){
maxArea = area;
maxContours = Object[i];
}
}
if(maxContours.size()>0){
vector<Moments> mu(maxContours.size());//计算图形矩
for (uint i = 0; i < maxContours.size(); i++)
{
mu[i] = moments(maxContours, false);
}
vector<Point2f> circle_center(maxContours.size());
for (uint i = 0; i < maxContours.size(); i++)
{
circle_center[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
// vector<Moments> mu(Object.size());
// for (uint i = 0; i < Object.size(); i++)
// {
// mu[i] = moments(Object[i], false);
// }
// vector<Point2f> circle_center(Object.size());
// for (uint i = 0; i < Object.size(); i++)
// {
// circle_center[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
// }
for (uint i = 0; i < Object.size(); i++)//画出中心点
{
circle(Origin_image,circle_center[i],4,Scalar(255,100,255),-1,8,0);
}
}
}
void show_Point(){
imshow("Result",Origin_image);
}
private:
int H_min,S_min,V_min;
int H_max,S_max,V_max;
};
object red;
int main(){
//------------GPIO-----------//
//在此示例中GPIO3为确认键,GPIO0为切换识别参数键,GPIO2为返回捕捉HSV参数模式键
if(wiringPiSetup()==-1){
return -1;
}
pinMode(0,INPUT);
pinMode(2,INPUT);
pinMode(3,INPUT);
//---------------------------//
Mat srcimage;
VideoCapture capture(0);
while(1){
if(digitalRead(3)==HIGH){ //识别按键
affirm=1;
}
if(digitalRead(0)==HIGH&&affirm==1){
Step=Step+1;
// printf("affirm:%d",affirm);
// printf("Step:%d\n",Step);
affirm=0;
}
if(digitalRead(2)==HIGH&&affirm==1){
if(flag==1){
flag=0;
}else{
flag=1;
}
affirm=0;
};
capture >> srcimage;
resize(srcimage,srcimage,Size(255,255));
cvtColor(srcimage, srcimageHSV, COLOR_BGR2HSV);
if(flag==0){ //HSV参数识别模式
// printf("%d\n",flag);
Mat imageROI=srcimageHSV(Rect(128,128,5,5));//ROI区域的设定
int histsize[] = { 256 };
float midranges[] = { 0,255 };
const float *ranges[] = { midranges };
MatND dsthist;
//*******进行HSV三层直方图的绘制*********//
int channels = 0;
calcHist(&imageROI, 1, &channels, Mat(), dsthist, 1, histsize, ranges, true, false);
double g_dhistmaxvalue;
minMaxLoc(dsthist, 0, &g_dhistmaxvalue, 0, 0);
for (int i = 0;i < 256;i++) {
int value = cvRound(256 * 0.9 *(dsthist.at<float>(i) / g_dhistmaxvalue));
if(value>max_value){
max_value=value;
H=i;
}
}
max_value=0;
channels = 1;
calcHist(&imageROI, 1, &channels, Mat(), dsthist, 1, histsize, ranges, true, false);
for (int i = 0;i < 256;i++) {
int value = cvRound(256 * 0.9 *(dsthist.at<float>(i) / g_dhistmaxvalue));
if(value>max_value){
max_value=value;
S=i;
}
}
max_value=0;
channels = 2;
calcHist(&imageROI, 1, &channels, Mat(), dsthist, 1, histsize, ranges, true, false);
for (int i = 0;i < 256;i++) {
int value = cvRound(256 * 0.9 *(dsthist.at<float>(i) / g_dhistmaxvalue));
if(value>max_value){
max_value=value;
V=i;
}
}
max_value=0;
//*********************************//
switch(Step){
case 1:
red.H=H;
red.S=S;
red.V=V;
red.srcimageHSV=srcimageHSV;
red.get_minmax();
red.tobe_threhold();
// red.show_image();
break;
}
rectangle(srcimage,Point(128,128),Point(134,134),Scalar(255,0,0),-1); //框出ROI区域范围
}
if(flag==1){ //动态目标识别模式
// printf("%d\n",flag);
red.tobe_threhold();
imshow("red",red.Mask);
red.Origin_image=srcimage;
red.calculate_Point();
// red.show_Point();
// red.Put_message();
}
imshow("origin", srcimage);
if(waitKey(10)==27){
break;
}
}
return 0;
}