今天介紹了簡單的圖像處理算法,基本屬於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++上的非常多的疑問,還專門找了參考書給我,非常感謝!