时间为友,记录点滴。
聊了这么多的图片运算,忽然有个想法,为什么非要用静态的图片来展示运算呢?我们可以用自己做的图片来经过运算后显示出来。说干就干。
先想一下需求:
- 整体环境非黑即白。
- 可以用鼠标在背景上画出矩形,矩形内容要填充成反色。
- 可以通过鼠标画的矩形展示图片的逻辑操作。
好就这吧,怎么而实现呢?老规矩,大象放冰箱的三步走:
OpenCV中的矩形类实现
rect
创建一个矩形:rect(X0, Y0, width, height), X0/Y0代表矩形的起点,width, height代表矩形的宽和高。这四个变量就把矩形的位置和大小限定了。
- area(): 面积
- size(): 尺寸,及[width, height]
- tl():
- br():
- width():
- heigth():
- contains(Point(x, y)):
- &:
- | :
- ==:
- 平移:rect = rect + Point(x, y); 其实就是对左上顶点坐标做加法
- 缩放:rect = rect + Size(x, y);其实就是对width和height做加法。
rectangle
void rectangle(InputOutputArray img, Point pt1, Point pt2,
const Scalar& color, int thickness = 1,
int lineType = LINE_8, int shift = 0);
- img: 可以认为是Mat 类型的Image.
- pt1: 矩形的一个顶点,比如:rect.tl
- pt2:矩形的pt1的对立顶点,比如:rect.br
- color: 矩形的颜色值或者灰度值。
- thickness: 是否需要填充 thickness>0?不填充:填充
- lineType: 线的类型,参考LineTypes
- shift Number of fractional bits in the point coordinates.
OpenCV中的鼠标实现画矩形
鼠标先知道一个函数就够了
void setMousecallback(const string& winname, MouseCallback onMouse, void* userdata=0)
- winname:窗口的名字
- onMouse:鼠标响应函数,回调函数。指定窗口里每次鼠标时间发生的时候,被调用的函数指针。 这个函数的原型应该为void on_Mouse(int event, int x, int y, int flags, void* param);
- userdate:传给回调函数的参数
void on_Mouse(int event, int x, int y, int flags, void* param);
- event:
常见的event:
cv2_EVENT_MOUSEMOVE 鼠标滑动
cv2_EVENT_LBUTTONDOWN 左键点击
cv2_EVENT_RBUTTONDOWN 右键点击
cv2_EVENT_MBUTTONDOWN 中间点击
cv2_EVENT_LBUTTONUP 左键释放
cv2_EVENT_RBUTTONUP 右键释放
cv2_EVENT_MBUTTONUP 中间释放
cv2_EVENT_LBUTTONDBLCLK 左键双击
cv2_EVENT_RBUTTONDBLCLK 右键双击
cv2_EVENT_MBUTTONDBLCLK 中间双击
- x/y: 鼠标指针在图像坐标系的坐标(不是窗口坐标系)
- flags: CV_EVENT_FLAG的组合, param是用户定义的传递到setMouseCallback函数调用的参数。
cv2_EVENT_FLAG_LBUTTON 左键拖拽
cv2_EVENT_FLAG_RBUTTON 右键拖拽
OpenCV中的图片逻辑操作
//逻辑运算:
//dst = src1 & src2
void bitwise_and(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());
//dst = src1 | src2
void bitwise_or(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());
//dst = src1 ^ src2
void bitwise_xor(InputArray src1, InputArray src2,OutputArray dst, InputArray mask=noArray());
//dst = ~src
void bitwise_not(InputArray src, OutputArray dst,InputArray mask=noArray());
好了,完成了构思,和基本的概念,coding。。。
第一步:先实现一个矩形类,并且把它画出来,看看基本的&|操作是否有用。
static void drawRectWindow(Mat img, Rect rect)
{
rectangle(img, rect, Scalar(255), -1);
}
static void rectTest()
{
Mat imgBackGround = Mat::zeros(600, 800, CV_8UC1);
Rect test1(100, 100, 200, 200);
Rect test2(200, 200, 200, 200);
Rect test3 = test1 | test2;
Rect test4 = test1 & test2;
showRectPara("test1", test1);
showRectPara("test2", test2);
showRectPara("test1 | test2", test3);
showRectPara("test1 & test2", test4);
drawRectWindow(imgBackGround, test4);
namedWindow("Test");
imshow("Test", imgBackGround);
}
static void showRectPara(String name, Rect rect)
{
static uint number = 0;
cout << "n-------------------" << name << "-" << number << "--------------------" << endl;
cout << "area: " << rect.area() << endl;
cout << "size: " << rect.size() << endl;
cout << "TopLeft: " << rect.tl() << endl;
cout << "BottomRight: " << rect.br() << endl;
cout << "width: " << rect.width << endl;
cout << "height " << rect.height << endl;
number++;
}
打印输出:
矩形的一些属性
图片输出的是test1 &amp;amp;amp; test2
第二步:构造鼠标操作
注意点:
- 为了实现实时更新矩形,需要在while(1)的线程和callback函数中对矩形做动态调整。
- Not/And/Or的操作分别在“EVENT_LBUTTONUP” “EVENT_LBUTTONDOWN”时有操作的不同。
#include "pch.h"
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//宏定义
#define NOT_WINDOWS "NOT"
#define AND_WINDOWS "AND"
#define OR_WINDOWS "OR"
//全局变量
Rect gNotRectangle;
Rect gOrRectangle;
Rect gAndRectanglePre;
Rect gAndRectangleNew;
Rect gAndRectangle;
bool gbNotDrawingBox = false;
bool gbOrDrawingBox = false;
bool gbAndDrawingBox = false;
//Functions List
static void showRectPara(String name, Rect rect);
static void notMouseCallBall(int event, int x, int y, int flags, void* param);
static void orMouseCallBall(int event, int x, int y, int flags, void* param);
static void andMouseCallBall(int event, int x, int y, int flags, void* param);
static void drawRectWindow(Mat img, Rect rect);
static void rectTest();
int main()
{
Mat imgBackGround = Mat::zeros(600, 800, CV_8UC1);
Mat notImgTemp = imgBackGround.clone();
Mat orImgTemp = imgBackGround.clone();
Mat andImgTemp = imgBackGround.clone();
gNotRectangle = Rect(-1, -1, 0, 0);
gOrRectangle = Rect(-1, -1, 0, 0);
gAndRectanglePre = Rect(-1, -1, 0, 0);
gAndRectangleNew = Rect(-1, -1, 0, 0);
gAndRectangle = Rect(-1, -1, 0, 0);
namedWindow(NOT_WINDOWS);
namedWindow(OR_WINDOWS);
namedWindow(AND_WINDOWS);
imshow(NOT_WINDOWS, imgBackGround);
imshow(OR_WINDOWS, imgBackGround);
imshow(AND_WINDOWS, imgBackGround);
setMouseCallback(NOT_WINDOWS, notMouseCallBall, (void*)¬ImgTemp);
setMouseCallback(OR_WINDOWS, orMouseCallBall, (void*)&orImgTemp);
setMouseCallback(AND_WINDOWS, andMouseCallBall, (void*)&andImgTemp);
//rectTest();
while (true)
{
if (gbNotDrawingBox)
{
drawRectWindow(notImgTemp, gNotRectangle);
imshow(NOT_WINDOWS, notImgTemp);
}
if (gbOrDrawingBox)
{
drawRectWindow(orImgTemp, gOrRectangle);
imshow(OR_WINDOWS, orImgTemp);
}
if (gbAndDrawingBox)
{
drawRectWindow(andImgTemp, gAndRectangleNew);
imshow(AND_WINDOWS, andImgTemp);
}
if (waitKey(10) == 27)
{
break;
}
}
waitKey(0);
return true;
}
static void notMouseCallBall(int event, int x, int y, int flags, void* param)
{
Mat& img = *(Mat*)param;
Mat notImgTemp = img.clone();
int deltaX, deltaY;
static int oriX = 0;
static int oriY = 0;
switch (event)
{
case EVENT_MOUSEMOVE:
if (gbNotDrawingBox)
{
deltaX = x - oriX;
deltaY = y - oriY;
if (deltaX >= 0 && deltaY >= 0)
{
gNotRectangle = Rect(oriX, oriY, deltaX, deltaY);
}
else if (deltaX >= 0 && deltaY < 0)
{
gNotRectangle = Rect(oriX, y, deltaX, -1*deltaY);
}
else if (deltaX < 0 && deltaY >= 0)
{
gNotRectangle = Rect(x, oriY, -1*deltaX, deltaY);
}
else if (deltaX < 0 && deltaY < 0)
{
gNotRectangle = Rect(x, y, -1*deltaX, -1 * deltaY);
}
}
break;
case EVENT_LBUTTONDOWN:
gbNotDrawingBox = true;
oriX = x;
oriY = y;
img = 0;
//gNotRectangle = Rect(x, y, 0, 0);
break;
case EVENT_LBUTTONUP:
gbNotDrawingBox = false;
bitwise_not(img, notImgTemp);
//notImgTemp.copyTo(img);
imshow(NOT_WINDOWS, notImgTemp);
break;
default:
break;
}
}
static void andMouseCallBall(int event, int x, int y, int flags, void* param)
{
int deltaX, deltaY;
static int oriX = 0;
static int oriY = 0;
static bool isInit = false;
Mat& img = *(Mat*)param;
switch (event)
{
case EVENT_MOUSEMOVE:
if (gbAndDrawingBox)
{
deltaX = x - oriX;
deltaY = y - oriY;
if (deltaX >= 0 && deltaY >= 0)
{
gAndRectangleNew = Rect(oriX, oriY, deltaX, deltaY);
}
else if (deltaX >= 0 && deltaY < 0)
{
gAndRectangleNew = Rect(oriX, y, deltaX, -1 * deltaY);
}
else if (deltaX < 0 && deltaY >= 0)
{
gAndRectangleNew = Rect(x, oriY, -1 * deltaX, deltaY);
}
else if (deltaX < 0 && deltaY < 0)
{
gAndRectangleNew = Rect(x, y, -1 * deltaX, -1 * deltaY);
}
}
break;
case EVENT_LBUTTONDOWN:
gbAndDrawingBox = true;
oriX = x;
oriY = y;
gAndRectangleNew = Rect(x, y, 0, 0);
break;
case EVENT_LBUTTONUP:
cout << "isInit: " << isInit << endl;
if (false == isInit)
{
gAndRectanglePre = gAndRectangleNew;
isInit = true;
}
gbAndDrawingBox = false;
gAndRectangle = gAndRectangleNew & gAndRectanglePre;
showRectPara("Pre", gAndRectanglePre);
showRectPara("New", gAndRectangleNew);
showRectPara("Rect", gAndRectangle);
gAndRectanglePre = gAndRectangle;
img = 0;
drawRectWindow(img, gAndRectangle);
imshow(AND_WINDOWS, img);
break;
default:
break;
}
}
static void orMouseCallBall(int event, int x, int y, int flags, void* param)
{
int deltaX, deltaY;
static int oriX = 0;
static int oriY = 0;
switch (event)
{
case EVENT_MOUSEMOVE:
if (gbOrDrawingBox)
{
deltaX = x - oriX;
deltaY = y - oriY;
if (deltaX >= 0 && deltaY >= 0)
{
gOrRectangle = Rect(oriX, oriY, deltaX, deltaY);
}
else if (deltaX >= 0 && deltaY < 0)
{
gOrRectangle = Rect(oriX, y, deltaX, -1 * deltaY);
}
else if (deltaX < 0 && deltaY >= 0)
{
gOrRectangle = Rect(x, oriY, -1 * deltaX, deltaY);
}
else if (deltaX < 0 && deltaY < 0)
{
gOrRectangle = Rect(x, y, -1 * deltaX, -1 * deltaY);
}
}
break;
case EVENT_LBUTTONDOWN:
gbOrDrawingBox = true;
oriX = x;
oriY = y;
//gOrRectangle = Rect(x, y, 0, 0);
break;
case EVENT_LBUTTONUP:
gbOrDrawingBox = false;
break;
default:
break;
}
}
static void drawRectWindow(Mat img, Rect rect)
{
rectangle(img, rect, Scalar(255), -1);
}
static void rectTest()
{
Mat imgBackGround = Mat::zeros(600, 800, CV_8UC1);
Rect test1(100, 100, 200, 200);
Rect test2(200, 200, 200, 200);
Rect test3 = test1 | test2;
Rect test4 = test1 & test2;
showRectPara("test1", test1);
showRectPara("test2", test2);
showRectPara("test1 | test2", test3);
showRectPara("test1 & test2", test4);
drawRectWindow(imgBackGround, test4);
namedWindow("Test");
imshow("Test", imgBackGround);
}
static void showRectPara(String name, Rect rect)
{
static uint number = 0;
cout << "n-------------------" << name << "-" << number << "--------------------" << endl;
cout << "area: " << rect.area() << endl;
cout << "size: " << rect.size() << endl;
cout << "TopLeft: " << rect.tl() << endl;
cout << "BottomRight: " << rect.br() << endl;
cout << "width: " << rect.width << endl;
cout << "height " << rect.height << endl;
number++;
}
运行结果:
四个弹窗:log输出;&amp;amp;运算、|运算、非运算