如何实现视觉识别颜色
1. 功能说明
通过摄像头识别特定颜色(红、绿、蓝)。摄像头采集图像信息并通过WiFi将信息传递给PC端,然后PC端根据比例判断出目标颜色在色盘上的所属颜色后,指针便会指向对应颜色。

2. 电子硬件
本实验中采用了以下硬件:
主控板 |
Basra主控板(兼容Arduino Uno) |
扩展板 |
Bigfish2.1扩展板 |
电池 | 7.4V锂电池 |
通信 | 2510通信转接板 |
WiFi路由器 | |
其它 |
摄像头 |
配置OpenCV的Visual Studio 2015.net环境的计算机一台 |
3. 功能实现
工作原理:
① 摄像头采集图像信息;
② 通过WiFi将信息传递给PC端(VS2015配置的OpenCV环境);
③ 在PC端修改红色色域范围,用于判断摄像范围内的红色像素;
采用HSV颜色模型
④ 计算检测在显示的摄像范围内的红色像素区域所占比例=红色像素范围/显示的摄像范围;
⑤ 根据比例判断目标颜色在色盘上所属颜色;
⑥ 指针指向对应颜色。
3.1硬件连接
将摄像头与路由器连接,启动路由器,将PC连接到路由器的WIFI网络。
本实验不需要用到主控板作为下位机,可直接通过WiFi将图像信号传递给PC端,所以无需下位机编程。
主控板与WiFi正常连线,给WiFi路由器模块通电。
接线说明:
① 将2510通信转接板连接到扩展板的扩展坞上面;
② 找到1根USB线,一端连接到2510通信转接板接口上,另一端连接到WiFi路由器USB接口上;
③ 将摄像头线连接到WiFi路由器接口上。
3.2示例程序
下面提供一个可以进行3个颜色(红、绿、蓝)识别的参考例程(MainWindow.xaml.cs):
using System;using System.IO;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;using System.Windows.Media.Animation;using System.Threading;using OpenCvSharp;using System.Drawing;using System.Drawing.Imaging;namespace Color_Detect{/// <summary>/// Color_Detect/// </summary>public partial class MainWindow : System.Windows.Window{/ 指针角度对应各颜色* 25 -> 红色* 90 -> 绿色* 150 -> 蓝色*/int ANGLE_RED = 0;int ANGLE_GREEN = 0;int ANGLE_BLUE = 0;//各颜色像素所占窗口的比例double numOfred = 0.0;double numOfgreen = 0.0;double numOfblue = 0.0;//创建视频图像实例VideoCapture capture = new VideoCapture("http://192.168.8.1:8083/?action=stream");Mat frame = new Mat(); //存储视频每一帧图像像素Mat resultColor = new Mat(); //存储检测后的颜色像素//视频显示切换变量Boolean isChange = false;public MainWindow(){InitializeComponent();}private void Window_Loaded(object sender, RoutedEventArgs e){ANGLE_RED = 25;ANGLE_GREEN = 90;ANGLE_BLUE = 150;}//颜色指示动画函数int angelCurrent = 0;private void ColorIndicate(int where) {RotateTransform rt = new RotateTransform();rt.CenterX = 150;rt.CenterY = 185;this.indicatorPin.RenderTransform = rt;double timeAnimation = Math.Abs(angelCurrent - where) * 5;DoubleAnimation da = new DoubleAnimation(angelCurrent, where, new Duration(TimeSpan.FromMilliseconds(timeAnimation)));da.AccelerationRatio = 0.8;rt.BeginAnimation(RotateTransform.AngleProperty, da);switch (where) {case 25:colorDisplay.Content = "红色";break;case 90:colorDisplay.Content = "绿色";break;case 150:colorDisplay.Content = "蓝色";break;default:colorDisplay.Content = "颜色指示";break;}angelCurrent = where;}/// <summary>/// MatToBitmap(Mat image)/// </summary>public static Bitmap MatToBitmap(Mat image){return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image);}/// <summary>/// BitmapToBitmapImage(System.Drawing.Bitmap bitmap)/// </summary>public static BitmapImage BitmapToBitmapImage(Bitmap bitmap){using (MemoryStream stream = new MemoryStream()){bitmap.Save(stream, ImageFormat.Png); //格式选Bmp时,不带透明度stream.Position = 0;BitmapImage result = new BitmapImage();result.BeginInit();// According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."// Force the bitmap to load right now so we can dispose the stream.result.CacheOption = BitmapCacheOption.OnLoad;result.StreamSource = stream;result.EndInit();result.Freeze();return result;}}//颜色检测函数private void filterColor() {Mat hsvImage = frame.CvtColor(ColorConversionCodes.BGR2HSV);resultColor = new Mat(hsvImage.Rows, hsvImage.Cols, MatType.CV_8UC3, Scalar.All(255));double H = 0.0, S = 0.0, V = 0.0;float area = (float)(hsvImage.Rows * hsvImage.Cols);float rateOfred = 0, rateOfgreen = 0, rateOfblue = 0;for (int i = 0; i < hsvImage.Rows; i++) {for (int j = 0; j < hsvImage.Cols; j++) {H = hsvImage.Get<Vec3b>(i, j)[0];S = hsvImage.Get<Vec3b>(i, j)[1];V = hsvImage.Get<Vec3b>(i, j)[2];var color = frame.Get<Vec3b>(i, j);if (((H >= 0 && H <= 10) || (H >= 125 && H <= 180)) && S >= 43 && V >= 46) //红色像素所在hsv范围{resultColor.Set<Vec3b>(i, j, color);numOfred++;}else if ((H >= 33 && H <= 83) && S >= 43 && V >= 46) //绿色像素所在hsv范围{resultColor.Set<Vec3b>(i, j, color);numOfgreen++;}else if ((H > 100 && H < 124) && S >= 43 && V >= 46) //蓝色像素所在hsv范围{resultColor.Set<Vec3b>(i, j, color);numOfblue++;}}}rateOfred = (float)(numOfred) / area * 100;rateOfgreen = (float)(numOfgreen) / area * 100;rateOfblue = (float)(numOfblue) / area * 100;if (rateOfred > 85){ColorIndicate(ANGLE_RED);}else if (rateOfgreen > 85){ColorIndicate(ANGLE_GREEN);}else if (rateOfblue > 85) {ColorIndicate(ANGLE_BLUE);}numOfred = 0;numOfgreen = 0;numOfblue = 0;}//视频显示函数private void ThreadCapShow(){while (true){try{capture.Read(frame); // same as cvQueryFrameif (frame.Empty())break;this.Dispatcher.Invoke(new Action(delegate{if (isChange){filterColor();originImage.Source = BitmapToBitmapImage(MatToBitmap(resultColor));resultColor = null;}else {originImage.Source = BitmapToBitmapImage(MatToBitmap(frame));}}));//Cv2.WaitKey(100);//bitimg = null;}catch { }}}//加载视频private void loadBtn_Click(object sender, RoutedEventArgs e){if (originImage.Source != null) return;Thread m_thread = new Thread(ThreadCapShow);m_thread.IsBackground = true;m_thread.Start();}//切换视频显示,显示检测结果private void changeBtn_Click(object sender, RoutedEventArgs e){if (!isChange){isChange = true;changeBtn.Content = "返回";}else {isChange = false;changeBtn.Content = "切换";//指针角度归零ColorIndicate(0);}}}}
程序设定的颜色为红色、绿色、蓝色,可以使用色卡或者特定颜色的物体来检测。
注意:程序中的比例值设置为85%时,可以进行三种颜色的识别判断,建议测试的色块距离小一些,识别效果会更好。
4. 资料内容
识别颜色-例程源代码
资料内容详见 如何实现视觉识别-识别颜色