数字图像基本OP:利用OpenCV实现YOLO风格矩形框和标注Label

数字图像基本OP:利用OpenCV实现YOLO风格矩形框和标注Label

1.draw_box()函数的数组方式自实现

画矩形框实际就是画四条直线,本质就是图像像素访问与操作。所以也有3种方式实现,图像像素访问与操作可以看看这一篇博客记录:[OpenCV访问像素值方法]

注意:如果图片是灰度图,也就是单通道的,会先把它转成三通道的,也就是BGR图。

参数解释

  • Mat& image:输入图像
  • Point p1:矩形框左上顶点坐标
  • Point p2:矩形框右下顶点坐标
  • int color[3]:颜色,同OpenCV,分别是BGR
  • int width:矩形框线条宽度

插入方式如下图所示
在这里插入图片描述
数组方式实现draw_box代码

void draw_box_arr(Mat& image, Point p1, Point p2, int color[3], int width)
{
	if (image.channels() == 1)
	{
		cvtColor(image, image, COLOR_GRAY2BGR);
	}
	for (int h = p1.x; h <= p1.x + width; ++h)
	{
		for (int w = p1.y; w < p2.y; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
	for (int h = p1.x+width; h <= p2.x-width; ++h)
	{
		for (int w = p1.y; w < p1.y+width; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
	for (int h = p2.x-width; h <= p2.x ; ++h)
	{
		for (int w = p1.y; w < p2.y; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
	for (int h = p1.x+width; h <= p2.x - width; ++h)
	{
		for (int w = p2.y-width; w < p2.y; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
}

测试时分别使用了自己写的draw_box函数和OpenCV提供的rectangle函数来画矩形框,这里介绍一个OpenCV中测试代码运行实践的方法:

cv::int64 getTickCount() 
cv::double getTickFrequency()

//使用方法
double t = (double)getTickCount();
// do something ...
t = ((double)getTickCount() - t)/getTickFrequency();

最后t的值就是do sth运行的时间。

测试代码:

//draw_box_arr_test
double start = (double)getTickCount();
draw_box_arr(input_image, Point(40, 40), Point(200, 200), color, 1);
double t = (getTickCount() - start) / getTickFrequency();

//opencv_rectangle_test
double start1 = (double)getTickCount();
rectangle(input_image, Point(50,50), Point(210,210), Scalar(30, 255, 30), 1, 8, 0);
double t1 = (getTickCount() - start1) / getTickFrequency();

测试结果:
在这里插入图片描述

可以看得出来,消耗时间差距还是很明显的,如果使用指针方法应该会快很多。

2.draw_label()函数的自实现

draw_label()函数主要是添加一个指定颜色的背景,这样在图片中标注出来更方便观察。

void draw_label(Mat& image, Point p, int color[3],String s)
{
	//lable size:30 x slen*20+5
	int l_w = s.length() * 20 + 5;
	int l_h = 30;
	for (int h = p.x - l_h; h < p.x; h++)
	{
		uchar* current_row = image.ptr<uchar>(h);
		int x = p.y;
		while (x--!=0)
		{
			current_row++;
			current_row++;
			current_row++;
		}
		for (int w = p.y; w < p.y + l_w; w++)
		{
			*current_row++ = color[0];
			*current_row++ = color[1];
			*current_row++ = color[2];
		}
	}
	putText(image, s, Point(p.x + 5, p.y - 5), 2, 1, (0, 0, 0), 1, 8);
}

测试代码:

draw_label(input_image,Point(150, 150), color,"asdadasdas");

测试结果:
result_label

3.整合测试

最终结果如下所示:
在这里插入图片描述

完整代码:

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;

void draw_box_arr(Mat& image, Point p1, Point p2, int color[3], int width);
void draw_label(Mat& image, Point p1, int color[3],String s);

int main(int argc, char**argv)
{
	Mat input_image = imread("./whisper.jpg", 1);
	if (input_image.empty())
	{
		cout << "read input error!" << endl;
		return -1;
	}

	Point p1(90, 150);
	Point p2(250, 350);

	int color[3] = { 0,255,0 };
	draw_label(input_image,p1, color,"flower");
	draw_box_arr(input_image, p1, p2, color, 2);
	cv::imshow("result", input_image);
	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}

void draw_box_arr(Mat& image, Point p1, Point p2, int color[3], int width)
{
	if (image.channels() == 1)
	{
		cvtColor(image, image, COLOR_GRAY2BGR);
	}
	for (int h = p1.x; h <= p1.x + width; ++h)
	{
		for (int w = p1.y; w < p2.y; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
	for (int h = p1.x+width; h <= p2.x-width; ++h)
	{
		for (int w = p1.y; w < p1.y+width; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
	for (int h = p2.x-width; h <= p2.x ; ++h)
	{
		for (int w = p1.y; w < p2.y; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
	for (int h = p1.x+width; h <= p2.x - width; ++h)
	{
		for (int w = p2.y-width; w < p2.y; ++w)
		{
				Vec3b bgr = image.at<Vec3b>(h, w);
				bgr[0] = color[0];//b
				bgr[1] = color[1];//g
				bgr[2] = color[2];//r
				image.at<Vec3b>(h, w) = bgr;
		}
	}
}

void draw_label(Mat& image, Point p, int color[3],String s)
{
	//lable size:30 x slen*20+5
	int l_w = s.length() * 20 + 5;
	int l_h = 30;
	for (int h = p.x - l_h; h < p.x; h++)
	{
		uchar* current_row = image.ptr<uchar>(h);
		int x = p.y;
		while (x--!=0)
		{
			current_row++;
			current_row++;
			current_row++;
		}
		for (int w = p.y; w < p.y + l_w; w++)
		{
			*current_row++ = color[0];
			*current_row++ = color[1];
			*current_row++ = color[2];
		}
	}
	putText(image, s, Point(p.y+5,p.x-5), 2, 1, (0, 0, 0), 1, 4);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值