opencv3第4章例题
opencv4第4章例题1ASCII 打印机
建立一个500x500大小的单通道图像,每个像素值都为0
1.创建一个ASCII数字打字机,你可以在自己的电脑上输入数字,并在一个20像素高、10像素宽的方格中显示数字。当你键入时,数字从左到右显示,知道到达图像末尾才停止。
2.允许键入回车和退格。
3.允许使用箭头来编辑每个数字。
4.创建一个键来将输出图像转化为彩色图像,每个不同的数字由不同的颜色显示。
本次创建100x100像素图
#include <opencv.hpp>
#include<iostream>
#include <string>
#include<conio.h>
#include<time.h>
using namespace cv;
using namespace std;
Mat code(int num)
{
Mat num_code;
switch (num)
{
case '0':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for(int i=2;i!=8;i++)
{
num_code.at<uchar>(i, 1) = 255;
num_code.at<uchar>(i, 8) = 255;
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(8, i) = 255;
}
num_code.at<uchar>(1, 8) = 255;
num_code.at<uchar>(8, 8) = 255;
num_code.at<uchar>(1, 1) = 255;
num_code.at<uchar>(8, 1) = 255;
break;
case '1':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(i, 4) = 255;
}
break;
case '2':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i)=255;
num_code.at<uchar>(8, i)=255;
num_code.at<uchar>(5, i) = 255;
}
num_code.at<uchar>(2, 8) = 255;
num_code.at<uchar>(3, 8) = 255;
num_code.at<uchar>(4, 8) = 255;
num_code.at<uchar>(6, 1) = 255;
num_code.at<uchar>(7, 1) = 255;
break;
case '3':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(8, i) = 255;
num_code.at<uchar>(5, i) = 255;
num_code.at<uchar>(i, 8) = 255;
}
break;
case '4':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(i, 1) = 255;
num_code.at<uchar>(4, i) = 255;
num_code.at<uchar>(8, i) = 255;
}
break;
case '5':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(4, i) = 255;
num_code.at<uchar>(8, i) = 255;
}
num_code.at<uchar>(2,1) = 255;
num_code.at<uchar>(3, 1) = 255;
num_code.at<uchar>(1, 6) = 255;
num_code.at<uchar>(1, 7) = 255;
break;
case '6':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(4, i) = 255;
num_code.at<uchar>(8, i) = 255;
}
break;
case '7':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(i, 8) = 255;
}
break;
case '8':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(i, 8) = 255;
num_code.at<uchar>(i, 1) = 255;
num_code.at<uchar>(8, i) = 255;
num_code.at<uchar>(4, i) = 255;
}
break;
case '9':
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i != 8; i++)
{
num_code.at<uchar>(1, i) = 255;
num_code.at<uchar>(i, 8) = 255;
num_code.at<uchar>(8, i) = 255;
num_code.at<uchar>(4, i) = 255;
}
num_code.at<uchar>(2, 1) = 255;
num_code.at<uchar>(3, 1) = 255;
break;
default:
break;
}
return num_code;
}
Mat change_image_color(Mat src, int a, int b, int c)
{
Mat dst;
if (src.channels() == 1)
{
cvtColor(src, dst, COLOR_GRAY2BGR);
for(int i=0;i!=10;i++)
for (int j = 0; j != 10; j++)
{
if (dst.at<Vec3b>(j, i)[1] == 255)
{
dst.at<Vec3b>(j, i)[0] = a;
dst.at<Vec3b>(j, i)[1] = b;
dst.at<Vec3b>(j, i)[2] = c;
}
}
}
else if (src.channels() == 3)
{
dst = src.clone();
for (int i = 0; i != 10; i++)
for (int j = 0; j != 10; j++)
{
if (dst.at<Vec3b>(j, i)[0] == 255
&& dst.at<Vec3b>(j, i)[1] == 255
&& dst.at<Vec3b>(j, i)[2] == 255) //如果是白色,改变颜色
{
dst.at<Vec3b>(j, i)[0] = a;
dst.at<Vec3b>(j, i)[1] = b;
dst.at<Vec3b>(j, i)[2] = c;
}
}
}
else
{
cout << "Sorry, I can't deal with it!" << endl;
cout << "the result is src" << endl;
return src;
}
return dst;
}
int main()
{
cout << "ASSCII printer" << endl;
Mat screen = Mat(100, 100, CV_8UC1, Scalar(0));
char num;
Rect work_Roi;
work_Roi.x = 0;
work_Roi.y = 0;
work_Roi.width = 10;
work_Roi.height = 10;
Mat out_Roi = Mat(10, 10, CV_8UC1, Scalar(0));
bool flag = false;
namedWindow("打印机", WINDOW_NORMAL);
imshow("打印机", screen);
waitKey(0);
while (1)
{
cin >> num;
if (num >= '0' && num <= '9' && flag == false)
{
out_Roi = code(num);
out_Roi.copyTo(screen(work_Roi));
imshow("打印机", screen);
if (waitKey(10) == 27)
break;
if (work_Roi.y != 90 || work_Roi.x != 90)
{
if (work_Roi.x == 90)
{
work_Roi.x = 0;
work_Roi.y += 10;
}
else
{
work_Roi.x += 10;
}
}
else
{
work_Roi.x = 100;
work_Roi.y = 90;
cout << "已经到底了" << endl;
flag = true;
}
}
else if (num == 'n')
{
if (work_Roi.y != 100)
{
work_Roi.x = 0;
work_Roi.y += 10;
}
else
{
flag = true;
cout << "No space input number!" << endl;
}
}
//倒退
else if (num == 'b')
{
Mat back_ROI = Mat(10, 10, CV_8UC1, Scalar(0));
if (work_Roi.x != 0)
{
work_Roi.x -= 10;
}
else
{
if (work_Roi.y == 0)
cout << "This is the first location, please input something" << endl;
else
{
work_Roi.x = 90;
work_Roi.y -= 10;
}
}
back_ROI.copyTo(screen(work_Roi));
imshow("打印机", screen);
if (waitKey(10) == 27) break;
flag = false;
}
else if (num == 'c')
{
int a, b, c;
RNG rng((unsigned)time(NULL));
Mat screen_color(100, 100, CV_8UC3, Scalar(0, 0, 0));
Mat trasition_ROI(10,10 , CV_8UC3, Scalar(0, 0, 0));
Mat work_color_ROI(10,10,CV_8UC3, Scalar(0, 0, 0));
for(int i=0;i!=100;i+=10)
for (int j = 0; j != 100; j += 10)
{
a = rng.uniform(0, 256);
b = rng.uniform(0, 256);
c = rng.uniform(0, 256);
work_Roi.x = j;
work_Roi.y = i;
trasition_ROI = change_image_color(screen(work_Roi), a, b, c);
trasition_ROI.copyTo(screen_color(work_Roi));
}
imshow("打印机", screen_color);
waitKey(0);
break;
}
else
{
cout << "Please don't input number!" << endl;
cout << "Please try input 'b'" << endl;
}
}
return 0;
}
积分图
我们想要创建一个函数,通过创建一个统计图像来让矩形区域内的像素求和操作更有效率。这个统计图像的每个像素将储存从原点到它所包含矩形区域的所有像素值的和。这个图像也被称为“积分图”,通过使用积分图中四个点的值,我们可以得到它包含的矩形区域像素值的和。
创建一个100 x200单通道uchar图像,并使用随机数填充,创建一个100X 200单a通道浮点数并将所有成员置0。
按照定义计算积分图。
考虑如何有效利用已经计算得到的积分图加上新的数值来加速积分图计算,实现这个更高效的方法。
使用积分图像快速计算原始图像中任意矩形的像素之和。
考虑如何修改积分图像,以便可以有效计算出一个45度旋转矩形的和。详细描述算法。
#include <opencv.hpp>
#include<iostream>
#include <string>
#include<conio.h>
#include<time.h>
#include<math.h>
using namespace cv;
using namespace std;
//测试时间
void PrintMs(const char* text = " ")
{
static long long last = 0;
long long cur = getTickCount();
if (last == 0)
{
last = cur;
return;
}
long long ms = 0;
ms = ((double)(cur - last) / getTickFrequency()) * 1000;
if (*text != 0)
{
printf("%s = %dms\n", text, ms);
}
last = getCPUTickCount();
}
//加速积分图
void Intergral(Mat &src, Mat& des)
{
//第一行单独处理
float rs = 0.0f;
for (int i = 0; i < src.cols; i++)
{
rs+= src.at<uchar>(0, i);
des.at<float>(0, i) = rs;
}
for (int i = 1; i < src.cols; i++)
{
float rs = 0.0f;
for (int j = 0; j < src.rows; j++)
{
rs += src.at<uchar>(i, j);
des.at<float>(i, j) = rs + des.at<float>((i - 1), j);
}
}
}
//迭代常规积分图算法
void normal_Integral(Mat &src, Mat& des)
{
for (int i = 0; i < src.cols; i++)
{
for (int j = 0; j < src.rows; j++)
{
float temp = 0;
for (int ii = 0; ii <= i; ii++)
{
for (int jj = 0; jj <= j; jj++)
{
temp += src.at<uchar>(ii, jj);
}
}
//printf("%.2f ", temp);
//printf("%d ", src.at<uchar>(i, j));
des.at<float>(i, j) = (float)temp;
//printf("%f ", des.at<float>(i, j));
}
//printf("\n");
}
}
//积分图求矩形区域像素和
float sum(Rect rec,Mat& integral)
{
float total = 0.0f;
int i, j, ii, jj;
i = rec.x;
j = rec.y;
ii = i + rec.width;
jj = j + rec.height;
int x1, x2, x3, x4;
x1 = integral.at<float>(ii, jj);
x2 = integral.at<float>(ii, j);
x3 = integral.at<float>(i, j);
x4 = integral.at<float>(i, jj);
total = x1 + x3 - x2 - x4;
return total;
}
int main()
{
RNG rng((unsigned)time(NULL));
//Mat src = Mat(100,100, CV_8UC1,Scalar(0));
//行数小于列数会报错:CV_DbgAssert((unsigned)i0 < (unsigned)size.p[0]);
Mat src = Mat::zeros(4,4, CV_8UC1);
//PrintMs("starter");
printf("\n");
for (int i = 0; i < src.cols; i++)
for (int j = 0; j <src.rows; j++)
{
src.at<uchar>(j,i) = rng.uniform(0, 255);
}
printf("\n");
Mat des = Mat(src.size(), CV_32FC1, Scalar(0));
printf("src :%d %d", src.rows, src.cols);
printf("des :%d %d", des.rows, des.cols);
printf("\n");
for (int i = 0; i < src.cols; i++)
{
for (int j = 0; j < src.rows; j++)
{
printf("%d ", src.at<uchar>(i, j));
}
printf("\n");
}
printf("\n");
PrintMs("startTime");
//加速积分图
Intergral(src, des);
//迭代遍历常规算法
//normal_Integral(src, des);
PrintMs("endtime");
for (int i = 0; i < src.cols; i++)
{
for (int j = 0; j < src.rows; j++)
{
printf("%.2f ", des.at<float>(i, j));
}
printf("\n");
}
PrintMs("start integal");
PrintMs("end integal");
/*namedWindow("dst", WINDOW_AUTOSIZE);
imshow("dst", des);*/
//用积分图求矩形区域像素和,定义矩形区域
Rect rect(1, 1, 1, 1);
printf("rect area sum:%f\n", sum(rect, des));
waitKey(0);
return 0;
}
5-1
这个练习将使你熟悉许多函数使用矩阵类型的概念。创建一个三通道二维矩阵,字节类型,尺寸为100x100,并设置所有数值为0。
在矩阵中使用void cv::circle(InputOutputArray img, cv::point center,a.intradius, cv::Scalar color, int thickness=1, int ine type=8, intshift=0)画一个圆。
使用第2章所讲的方法来显示这幅图像。b.创建一个有三个通道的二维字节类型矩阵,尺寸为100x 100,并将所有值赋为0。使用cv::Mat元素访问函数修改像素。以(20,5)与(40,20)为顶点画一个绿色的长方形。
#include <opencv.hpp>
#include<iostream>
#include <string>
#include<conio.h>
#include<time.h>
using namespace std;
using namespace cv;
void MyLine(Mat src);
void MyRectangle(Mat src); //绘制矩形方法
void MyEllipse(Mat src); //绘制椭圆
void MyCircle(Mat &src); //绘制圆
void MyPolygon(Mat src); //绘制多边形
void rectangleInit(Mat& src);//绘制矩形方法并初始化
//void RandomLineDemo(Mat src); //随机画线
int main()
{
Mat src = Mat(300, 300, CV_8UC3, Scalar(0));
MyCircle(src); //是否使用引用,对图像显示不受影响MyCircle(Mat &src)
MyLine(src); //绘制线段
//MyRectangle(src);
//绘制文字
putText(src, "opencv test draw shape", Point(50, 50), FONT_ITALIC, 1.0, Scalar(0, 0, 255),2, LINE_AA, false);
//绘制矩形
rectangleInit(src);
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
waitKey(0);
return 0;
}
void rectangleInit(Mat& src)
{
Vec3b *p;
for(int x=0;x<src.rows;x++)
for (int y = 0; y < src.cols; y++)
{
src.at<Vec3b>(x, y) = 0;
}
MyRectangle(src);
}
//画线方法
void MyLine(Mat src)
{
Point p1 = Point(10, 20);
Point p2;
p2.x = 300;
p2.y = 300;
Scalar color = Scalar(0, 0, 255);
//画线
line(src, p1, p2, color, 2, LINE_8);
}
//绘制矩形方法
void MyRectangle(Mat src)
{
Rect rect = Rect(20, 5, 20, 15);
Scalar color = Scalar(0, 255, 0);
//绘制矩形
rectangle(src, rect, color, 2, LINE_8);
}
//绘制椭圆
void MyEllipse(Mat src)
{
Point center = Point(src.rows / 2, src.cols / 2);
Size seze = Size(src.cols / 4, src.rows / 8);
Scalar color = Scalar(0, 0, 255);
// 绘制椭圆
// 第一个参数表示绘图
// 第二个参数表示椭圆中心
// 第三个参数分别表示横轴, 纵轴长度,用Size类型表示
// 第四个参数表示顺时针倾斜角度
// 第五,六个参数表示从左上角逆时针开始绘制,绘制多少角度
//ellipse(src, center, size, 30, 0, 360, color, LINE_8,8,0);
}
//绘制圆
void MyCircle(Mat &src)
{
Scalar color = Scalar(0, 0, 255);
Point center = Point(src.rows / 4, src.cols / 2);
circle(src, center, 8, (0,0,255),-1);
}