今天介绍了简单的图像处理算法,基本属于OpenCV的入门算法。
之前使用过python版本的OpenCV,大部分操作已经被封装成可直接调用的函数,卷积可以直接通过numpy来实现,而C++中除了若干简单的滤波算法之外,没有其他的函数了。不过相比于Python,C++的好处在于速度快,对于对帧率要求比较高的设备来说,C++的优势还是非常明显。
由于各类算法大同小异(尤其是各类使用二维卷积的算法),因此只贴出主要结构和分析:
本次用到的源文件为:
- mipi_demo.cpp (main()函数所在文件)
- mipi_cam.cpp (mipi摄像头驱动)
- image_handle.cpp (图像处理函数所在文件)
摄像头驱动不做修改。
main函数所在文件只需要在while(1)循环中加入你写好的图像处理函数即可
主要介绍几个典型的图像处理代码:
1.直方图均衡
void histogram_equalization (const Mat src, Mat& dst)//直方图均衡
{
Mat gray,gray_end;//创建三个矩阵
if (!src.data || !dst.data)//一个判断
return;
double probability_gray[256] = {0};
//建立矩阵
gray.create(cv::Size(RGA_ALIGN(src.cols, 16), RGA_ALIGN(src.rows, 16)), CV_8UC1);//RGA_ALIGN用于对齐格式
gray_end.create(cv::Size(RGA_ALIGN(src.cols, 16), RGA_ALIGN(src.rows, 16)), CV_8UC1);
//rgb转灰度
rgb_to_gray(src, gray);
for (int i = 0 + 1; i < src.rows - 1; i++)//统计频次
{
for (int j = 0 + 1; j < src.cols - 1; j++)
{
probability_gray[gray.at<uchar>(i, j)] += 1;
}
}
//计算累计概率
for (int i = 1; i < 256; i++)
{
probability_gray[i] += probability_gray[i-1];
}
for (int i = 0; i < 256; i++)
{
probability_gray[i] /= 307200.0;
}
for (int i = 0 + 1; i < src.rows - 1; i++)
{
for (int j = 0 + 1; j < src.cols - 1; j++)
{
gray_end.at<uchar>(i, j) = (uchar)(probability_gray[gray.at<uchar>(i, j)] * 255.0);
}
}
fcv::cvtColor(gray_end, dst, CV_GRAY2BGR);//灰度转bgr
}
一些补充:
1 这段代码在计算流程上还可以优化,但可读性会下降(不需要除以307200,而是考虑255,一起计算,每帧可以减少307200次乘法计算)
2 这是将彩图转换灰度之后做的直方图均衡处理,如果要保持彩图,需要对RGB三个通道的矩阵分别做直方图均衡
2 卷积(以锐化效果为例)
void sharpen_flitering(const Mat src, Mat &dst)//锐化滤波器
{
Mat gray gray_end;//创建2个矩阵
signed char kernel[3][3] = {
{ 0, -1, 0},
{ -1, 5, 1},
{ 0, -1, 0}};
if (!src.data || !dst.data)//一个判断
return;
//建立矩阵
gray.create(cv::Size(RGA_ALIGN(src.cols, 16), RGA_ALIGN(src.rows, 16)), CV_8UC1);//RGA_ALIGN用于对齐格式
gray_end.create(cv::Size(RGA_ALIGN(src.cols, 16), RGA_ALIGN(src.rows, 16)), CV_8UC1);
//rgb转灰度
rgb_to_gray(src, gray);
for (int i = 0+1; i < src.rows-1; i++)
{
//uchar* p1 = gray.ptr<uchar>(i);//灰度图的一行
//uchar* p2 = gray_reverse.ptr<uchar>(i);//
uchar* q = gray_end.ptr<uchar>(i);
for (int j = 0+1; j < src.cols-1; j++)
{
gray_end.at<uchar>(i, j) = 0;
gray_end.at<uchar>(i, j) += gray.at<uchar>(i - 1, j - 1) * kernel[0][0];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i - 1, j - 0) * kernel[0][1];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i - 1, j + 1) * kernel[0][2];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i - 0, j - 1) * kernel[1][0];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i - 0, j - 0) * kernel[1][1];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i - 0, j + 1) * kernel[1][2];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i + 1, j - 1) * kernel[2][0];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i + 1, j - 0) * kernel[2][1];
gray_end.at<uchar>(i, j) += gray.at<uchar>(i + 1, j + 1) * kernel[2][2];
}
}
fcv::cvtColor(gray_end, dst, CV_GRAY2BGR);//灰度转bgr
}
一些补充:
1 代码仍可优化
2 修改卷积核,可以实现其他的效果
3 gray_end.at<uchar>(i, j) ,这句话表示gray_end的第(i,j)个像素的值
感谢:
非常感谢2位老师和杭宇学长的指导,尤其是杭宇学长,解决了我关于C++上的非常多的疑问,还专门找了参考书给我,非常感谢!