图像掩模的作用:
①提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区域内图像值保持不变,而感兴趣区域外图像值都为0。
②屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
③结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩模相似的结构特征。
④特殊形状图像的制作。
#include "opencv2/opencv.hpp"
#include<iostream>
#include <math.h>
using namespace std;
using namespace cv;
Mat temp, frame;
Mat MoveDetect(Mat background, Mat img)
{
//将background和img转为灰度图
Mat result = img.clone();
Mat gray1, gray2;
cvtColor(background, gray1, CV_BGR2GRAY);
cvtColor(img, gray2, CV_BGR2GRAY);
//进行canny边缘检测
Canny(background, background, 0, 30, 3);
//将background和img做差;对差值图diff进行阈值化处理
Mat diff;
absdiff(gray1, gray2, diff);
//imshow("absdiss", diff);
threshold(diff, diff, 50, 255, CV_THRESH_BINARY);
//imshow("threshold", diff);
//腐蚀膨胀消除噪音
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat element2 = getStructuringElement(MORPH_RECT, Size(11, 11));
erode(diff, diff, element);
//imshow("erode", diff);
dilate(diff, diff, element2);
//imshow("dilate", diff);
//查找并绘制轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//查找正外接矩形
int x0 = 0, y0 = 0, w0 = 0, h0 = 0;
double Area = 0, AreaAll = 0;
for (int i = 0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
x0 = boundRect[i].x;
y0 = boundRect[i].y;
w0 = boundRect[i].width;
h0 = boundRect[i].height;
//计算面积
double Area = contourArea(contours[i]);
AreaAll = Area + AreaAll;
if (w0 > 50 && h0 > 50)
{
Mat CameraPicMask, CameraImg, ProjectorPicMask, ProjectorImg;
Mat ProjectorPic, ProjectorPicClone;
Mat CameraImageROI, ProjectorImageROI;
ProjectorPic = imread("0002.jpg");
ProjectorPic.copyTo(ProjectorPicClone);
rectangle(result, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
CameraImageROI = { Scalar(0, 0, 0) };
rectangle(ProjectorPic, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8);
ProjectorImageROI = ProjectorPic(Rect(Point(x0, y0), Point(x0 + w0, y0 + h0)));
ProjectorImageROI = { Scalar(0, 0, 0) };
imshow("ProjectorImgB", ProjectorPic);
CameraPicMask = Mat::zeros(frame.size(), CV_8UC1);
Rect rect = (Rect(Point(x0, y0), Point(x0 + w0, y0 + h0)));
CameraPicMask(rect).setTo(255);
frame.copyTo(CameraImg, CameraPicMask);
ProjectorPicMask = Mat::zeros(ProjectorPic.size(), CV_8UC1);
ProjectorPicMask(rect).setTo(255);
ProjectorPicClone.copyTo(ProjectorImg, ProjectorPicMask);
imshow("CameraImgB", CameraImg);
imshow("CameraPicMask", CameraPicMask);
imshow("ProjectorImgA", ProjectorImg);
//imshow("ProjectorPicMask", ProjectorPicMask);
}
//文字输出
Point org(10, 35);
if (i >= 1 && AreaAll >= 19600)
putText(result, "Is Blocked ", org, CV_FONT_HERSHEY_SIMPLEX, 0.8f, Scalar(0, 255, 0), 2);
}
return result;
}
void main()
{
VideoCapture cap;
cap.open(0);
if (!cap.isOpened()) //检查打开是否成功
return;
Mat result, background;
int count = 0;
while (1)
{
cap >> frame;
if (!frame.empty())
{
count++;
if (count == 1)
/*background = frame.clone(); //背景差
result = MoveDetect(background, frame);*/
result = MoveDetect(frame, frame); //帧差
else
result = MoveDetect(temp, frame);
imshow("CameraImgA", result);
temp = frame.clone();
if (waitKey(50) == 27)
break;
}
else
continue;
}
cap.release();
}
VS下Dll程序:
#include<opencv2/opencv.hpp>
using namespace cv;
//..\..\UnityActivate\VSActivateUnity.exe
#define EXPORT_API __declspec(dllexport)
VideoCapture my_camera;
Mat temp, my_frameBGR;
int m_width = 640;
int m_height = 480;
Mat background;
int count = 0;
int test = 0;
Mat MoveDetect(Mat background, Mat tex)
{
//将background和img转为灰度图
Mat result = tex.clone();
Mat gray1, gray2;
cvtColor(background, gray1, CV_BGR2GRAY);
cvtColor(tex, gray2, CV_BGR2GRAY);
//进行canny边缘检测
Canny(background, background, 0, 30, 3);
//将background和img做差;对差值图diff进行阈值化处理
Mat diff;
absdiff(gray1, gray2, diff);
//imshow("absdiss", diff);
threshold(diff, diff, 50, 255, CV_THRESH_BINARY);
//imshow("threshold", diff);
//二值化后使用中值滤波+膨胀
Mat element = getStructuringElement(MORPH_RECT, Size(11, 11));
medianBlur(diff, diff, 5);//中值滤波
//imshow("medianBlur", diff);
dilate(diff, diff, element);
//blur(diff, diff, Size(10, 10)); //均值滤波
//imshow("dilate", diff);
//查找并绘制轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarcy;
findContours(diff, contours, hierarcy, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE); //查找轮廓
vector<Rect> boundRect(contours.size()); //定义外接矩形集合
//drawContours(img2, contours, -1, Scalar(0, 0, 255), 1, 8); //绘制轮廓
//查找正外接矩形
int x0 = 0, y0 = 0, w0 = 0, h0 = 0;
double Area = 0, AreaAll = 0;
for (int i = 0; i<contours.size(); i++)
{
boundRect[i] = boundingRect((Mat)contours[i]); //查找每个轮廓的外接矩形
x0 = boundRect[i].x;
y0 = boundRect[i].y;
w0 = boundRect[i].width;
h0 = boundRect[i].height;
//计算面积
double Area = contourArea(contours[i]);//计算第i个轮廓的面积
AreaAll = Area + AreaAll;
//筛选
if (w0 > 50 && h0 > 50)
{
//rectangle(result, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8);
Mat CameraPicMask, CameraImg, ProjectorPicMask, ProjectorImg;
Mat ProjectorPic, ProjectorPicClone;
Mat CameraImageROI, ProjectorImageROI;
ProjectorPic = imread("F:\\Unity\\Unity工程\\New Unity Project\\Assets\\Textures\\0003.jpeg");
ProjectorPic.copyTo(ProjectorPicClone);
rectangle(result, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8); //绘制第i个外接矩形
CameraImageROI = { Scalar(0, 0, 0) };
rectangle(ProjectorPic, Point(x0, y0), Point(x0 + w0, y0 + h0), Scalar(0, 255, 0), 2, 8);
ProjectorImageROI = ProjectorPic(Rect(Point(x0, y0), Point(x0 + w0, y0 + h0)));
ProjectorImageROI = { Scalar(0, 0, 0) };
imshow("ProjectorImgB", ProjectorPic);
/*CameraPicMask = Mat::zeros(my_frameBGR.size(), CV_8UC1);
Rect rect = (Rect(Point(x0, y0), Point(x0 + w0, y0 + h0)));
CameraPicMask(rect).setTo(255);
my_frameBGR.copyTo(CameraImg, CameraPicMask);*/
Rect rect = (Rect(Point(x0, y0), Point(x0 + w0, y0 + h0)));
ProjectorPicMask = Mat::zeros(ProjectorPic.size(), CV_8UC1);
ProjectorPicMask(rect).setTo(255);
ProjectorPicClone.copyTo(ProjectorImg, ProjectorPicMask);
//imshow("CameraImgB", CameraImg);
//imshow("CameraPicMask", CameraPicMask);
imshow("ProjectorImgA", ProjectorImg);
//imshow("ProjectorPicMask", ProjectorPicMask);
}
//文字输出
Point org(10, 35);
if (i >= 1 && AreaAll >= 19600)
{
putText(result, "Is Blocked ", org, CV_FONT_HERSHEY_SIMPLEX, 0.8f, Scalar(0, 255, 0), 2);
test = 1;
}
else
test = 0;
}
return result;
}
extern "C" bool EXPORT_API openCamera()
{
bool my_open = false;
while (!my_camera.isOpened())
{
//std::cout << "Cannot open the camera!" << std::endl;
my_camera.open(0);
}
my_camera.set(CV_CAP_PROP_FRAME_WIDTH, m_width);
my_camera.set(CV_CAP_PROP_FRAME_HEIGHT, m_height);
if (my_camera.isOpened())
{
my_open = true;
}
return my_open;
}
extern "C" void EXPORT_API recieveFrame(uchar* texturePtr)
{
Mat my_frameBGR;
Mat my_frameRBG;
Mat result;
my_camera >> my_frameBGR;
if (my_frameBGR.data)
{
cvtColor(my_frameBGR, my_frameRBG, CV_BGR2RGB);
memcpy(texturePtr, my_frameRBG.data, my_frameRBG.cols*my_frameRBG.rows*my_frameRBG.channels()*sizeof(uchar));
count++;
if (count == 1)
/*background = my_frameBGR.clone();
result = MoveDetect(background, my_frameBGR);*/
result = MoveDetect(my_frameBGR, my_frameBGR);
else
result = MoveDetect(temp, my_frameBGR);
temp = my_frameBGR.clone();
imshow("CameraImg", result);
}
}
extern "C" void EXPORT_API Quit()
{
destroyAllWindows();
}
extern "C" bool EXPORT_API num()
{
if (test != 0)
{
return true;
}
else
return false;
}
Unity中对应Dll的C#脚本:
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;//用c++中dll文件需要引入
public class Dll: MonoBehaviour
{
[DllImport("MyDll")]
public static extern bool openCamera();
[DllImport("MyDll")]
public static extern void recieveFrame(byte[] imageData);
[DllImport("MyDll")]
public static extern void Quit();
[DllImport("MyDll")]
public static extern bool num();
public bool IsOpen = false;
public byte[] imageData;
public Texture2D tex;
public int Width = 640;
public int Length = 480;
// Use this for initialization
void Start()
{
//open one camera
IsOpen = openCamera();
if (IsOpen)
{
imageData = new byte[Length * Width * 3];
tex = new Texture2D(Width, Length, TextureFormat.RGB24, false);
}
}
// Update is called once per frame
void Update()
{
//update one camera
if (IsOpen)
{
recieveFrame(imageData);
tex.LoadRawTextureData(imageData);
tex.Apply();
GetComponent<Renderer>().material.mainTexture = tex;
}
if (num())
print(num());
}
private void OnApplicationQuit()
{
Quit();
}
void OnGUI()
{
if (!IsOpen)
{
//string myword = "打开相机失败!";
string myword = "camera pause for a while!";
GUI.TextArea(new Rect(200, 100, 200, 50), myword, new GUIStyle());
}
//to get the button
GUI.color = Color.yellow;
GUI.backgroundColor = Color.red;
if (GUI.Button(new Rect(40, 50, 60, 30), "continue"))
{
IsOpen = true;
}
GUI.color = Color.white;
GUI.backgroundColor = Color.green;
if (GUI.Button(new Rect(40, 100, 60, 30), "pause"))
{
IsOpen = false;
}
GUI.color = Color.white;
GUI.backgroundColor = Color.blue;
}
}