baoli,暴力方法:
jifen, 积分图方法:c++ vector
jifen point, 积分图指针方法:不使用vector,速度有提升
col,列积分: 图像边缘未过滤
col2,列积分:图像边缘过滤方法同积分图方法
opencv, opencv的boxFilter方法
// filter_im.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <cstdlib>
#include<opencv2\opencv.hpp> // 导入opencv
using namespace std;
using namespace cv;
typedef unsigned char uchar;
#define PIXEL(frame, W, x, y) (frame+(y)*3*(W)+(x)*3)
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define Clip(a,min,max) ((a)<(min)?(min):((a)>(max)?(max):(a)))
//暴力
int filter_box_v(uint8_t r[], uint8_t r_filter[], int radiu, int height, int width) {
//float* r_filter = (float*)malloc(HEIGHT * WIDTH * sizeof(float));
//if (r_filter != NULL) {
// memset(r_filter, 0, HEIGHT * WIDTH * sizeof(float));
//}
//else {
// printf("error happend !! ");
// return -1;
//}
int cnt = (2 * radiu + 1) * (2 * radiu + 1);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int ave = 0;
for (int id = -radiu; id <= radiu; id++) {
for (int jd = -radiu; jd <= radiu; jd++) {
int ii = i + id;
int jj = j + jd;
if (ii < 0) ii = 0;
if (ii >= height) ii = height - 1;
if (jj < 0) jj = 0;
if (jj >= width) jj = width - 1;
ave += r[ii * width + jj];
}
}
r_filter[i * width + j] = (uint8_t)(ave / cnt);
//if (i % 40 == 0 && j % 40 == 0) {
// printf("%d,%d,%d,%d ", ave, cnt, ave / cnt, r[i + width + j]);
// //printf("%d,%d,%d,%d ", rr, rr1, cc, cc1);
//}
}
//if (i % 40 == 0) {
// printf("\n");
//}
}
return 1;
}
int filter_box_fast(uint8_t r[], uint8_t r_filter[], int radiu, int height, int width) {
int x, y;
uint8_t* p_add, * p_del, * p_res;
long long sum;
long long sum_col[1001];
int N = 2 * radiu + 1;
int c = (1 << 23) / (N * N);
memset(sum_col, 0, sizeof(long long) * width);
//前N行的列积分
for (y = 0, p_add = r; y < N; y++)
{
for (x = 0; x < width; x++)
{
sum_col[x] += *(p_add++);
}
}
//滤波
for (y = radiu, p_res = r_filter + y * width, p_del = r; y < height - radiu; y++)
{
sum = 0;
for (x = 0; x < N; x++)//N 列
{
sum += sum_col[x];
}
p_res += radiu;
for (x = radiu; x < width - radiu; x++) {
*(p_res++) = (sum*c)>>23;//sum / (N * N);
sum -= sum_col[x - radiu];
sum += sum_col[x + radiu + 1];
}
p_res += radiu;
//更新 sum_col
for (x = 0; x < width; x++) {
sum_col[x] -= *(p_del++);
sum_col[x] += *(p_add++);
}
}
return 1;
}
int filter_box_fast2(uint8_t r[], uint8_t r_filter[], int radiu, int height, int width) {
int x, y;
uint8_t* p_add, * p_del, * p_res;
long long sum;
long long sum_col[1001];
int N = 2 * radiu + 1;
int c = (1 << 23) / (N * N);
memset(sum_col, 0, sizeof(long long) * width);
//前radiu+1 行的列积分
for (y = 0, p_add = r; y < radiu+1; y++)
{
for (x = 0; x < width; x++)
{
sum_col[x] += *(p_add++);
}
}
//滤波
#define Ra (0)
int rr, cc, rr1, cc1, cnt;
for (y = Ra, p_res = r_filter + y * width, p_del = r; y < height - Ra; y++)
{
sum = 0;
for (x = 0; x < radiu+1; x++)//N 列
{
sum += sum_col[x];
}
p_res += Ra;
for (x = Ra; x < width - Ra; x++) {
rr = Max(0, y - radiu);
cc = Max(0, x - radiu);
rr1 = Min(height-1, y + radiu);
cc1 = Min(width-1, x + radiu);
cnt = (rr1 - rr + 1) * (cc1 - cc + 1);
*(p_res++) = sum / cnt;// (sum * c) >> 23;//sum / (N * N);
if(x - radiu >= 0)
sum -= sum_col[x - radiu];
if(x + radiu + 1 < width)
sum += sum_col[x + radiu + 1];
}
p_res += Ra;
//更新 sum_col
for (x = 0; x < width; x++) {
if(y >= radiu)
sum_col[x] -= *(p_del++);
if(y + radiu + 1 < height)
sum_col[x] += *(p_add++);
}
}
return 1;
}
int filter_box_v2(uint8_t r[], uint8_t r_filter[], int radiu, int height, int width) {
//for (int i = 0; i < height; i+=40) {
// for (int j = 0; j < width; j+=40) {
// printf("%d ",r[i * width + j]);
// }
// printf("\n");
//}
//intergate
//printf("sum:\n\n");
vector<vector<long long>> sumv(height+1, vector<long long> (width+1, 0));
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
sumv[i+1][j+1] = -sumv[i][j]+ sumv[i+1][j] + sumv[i][j+1] + r[i*width+j];
}
}
int sumt = 0;
int rr, cc, rr1, cc1, cnt;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
rr = max(1,i - radiu);
cc = max(1,j - radiu);
rr1 = min(height, i + radiu);
cc1 = min(width, j + radiu);
cnt = (rr1 - rr + 1) * (cc1 - cc + 1);
sumt = (int)(sumv[rr1][cc1] - sumv[rr1][cc - 1] - sumv[rr - 1][cc1] + sumv[rr - 1][cc - 1]);
r_filter[i * width + j] = (uint8_t)(sumt / cnt);
}
}
return 1;
}
int filter_box_v3(uint8_t r[], uint8_t r_filter[], int radiu, int height, int width) {
long long* sumv =( long long* )malloc(801*801*sizeof(long long));
//vector<vector<long long>> sumv(height + 1, vector<long long>(width + 1, 0));
memset(sumv, 0, sizeof(sumv));
int pos;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pos = i * width + j;
sumv[pos+width+1] = -sumv[pos] + sumv[pos+width] + sumv[pos + 1] + r[pos];
}
}
int sumt = 0;
int rr, cc, rr1, cc1, cnt;
int pos1, pos2, pos3, pos4;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
rr = max(1, i - radiu);
cc = max(1, j - radiu);
rr1 = min(height, i + radiu);
cc1 = min(width, j + radiu);
cnt = (rr1 - rr + 1) * (cc1 - cc + 1);
pos1 = rr1 * width + cc1;
pos2 = rr1 * width + cc - 1;
pos3 = (rr - 1) * width + cc1;
pos4 = (rr - 1) * width + cc - 1;
sumt = (int)(sumv[pos1] - sumv[pos2] - sumv[pos3] + sumv[pos4]);
r_filter[i * width + j] = (uint8_t)(sumt / cnt);
}
}
free(sumv);
return 1;
}
int get_data(cv::Mat& im, float* r, float* g, float* b, int height, int width) {
assert(height == im.rows);
assert(width == im.cols);
assert(3 == im.channels());
const int num = height * width;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int pos = i * width + j;
uint8_t* p = PIXEL(im.data, width, j, i);
r[i * width + j] = p[2] / 255.0f;
g[i * width + j] = p[1] / 255.0f;
b[i * width + j] = p[0] / 255.0f;
//printf("ddd: %d, %d, %d", p[2], p[1], p[0]);
}
}
return 1;
}
/*
void filter_by_sum(int* sum_img, int height, int width, int M, int N, uint8_t* im_filter) {
int* py1, * py2;
uint8_t* im_res;
int halfx, halfy;
int x, y, x1, y1;
int sum, c;
//init
//M, N is filter len,should be odd
}
*/
int main()
{
//d
std::cout << "Hello World!\n";
Mat image; //
//image = imread("D:\\MedData\\dark_mask\\002.jpg"); // 以绝对地址导入图片,图片路径是自己设置的
image = imread("D:\\dataset\\wang\\ccm\\2022-06-21-15-08-20_raw_gamma3.png");
int width = 800;
int height = 800;
cv::Size dsize = cv::Size(height, width);
cv::Mat img;
cv::resize(image, img, dsize, 0, 0, cv::INTER_AREA);
if (img.empty()) // 判断是否导入图片
{
cout << "请确认图片正确位置!" << endl;
return -1; // 返回-1
}
namedWindow("test", WINDOW_NORMAL); // 创建一个常规窗口
imshow("test", img); // 展示图片
waitKey(0); // 获取键盘按键响应
cv::imwrite("im_00.png", img);
Mat img2;
img.copyTo(img2);
clock_t start_time;
clock_t finish_time;
float program_time;
int radiu = 9;
Mat rgb[3], rgb2[3];
split(img, rgb);
split(img2, rgb2);
printf("%p,%p ", rgb[0].data, rgb2[0].data);
uint8_t* b = rgb[0].data;
uint8_t* g = rgb[1].data;
uint8_t* r = rgb[2].data;
uint8_t* b2 = rgb2[0].data;
uint8_t* g2 = rgb2[1].data;
uint8_t* r2 = rgb2[2].data;
//for (int i = 0; i < height; i+=40) {
// for (int j = 0; j < width; j+=40){
// printf("%d ", r[i*width+j]);
// }
// printf("\n");
// }
// printf("\n");
start_time = clock();
filter_box_v(r, r2, radiu, height, width);
filter_box_v(g, g2, radiu, height, width);
filter_box_v(b, b2, radiu, height, width);
finish_time = clock();
program_time = (float)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("Program complete time baoli: %f\n", program_time);
merge(rgb2, 3, img2);
imshow("baoli", img2); // 展示图片
waitKey(0);
cv::imwrite("im_baoli.png", img2);
img.copyTo(img2);
start_time = clock();
filter_box_v2(r, r2, radiu, height, width);
filter_box_v2(g, g2, radiu, height, width);
filter_box_v2(b, b2, radiu, height, width);
finish_time = clock();
program_time = (float)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("Program complete time jifen: %f\n", program_time);
merge(rgb2, 3, img2);
imshow("jifen", img2); // 展示图片
waitKey(0);
cv::imwrite("im_jifen.png", img2);
//Mat img3(height, width, CV_32FC3, 1/255.0);
//Mat img4(height, width, CV_32FC3, 1/255.0);
//img.convertTo(img3, CV_32FC3);
//img2.convertTo(img4, CV_32FC3);
img.copyTo(img2);
start_time = clock();
boxFilter(img, img2, 8, Size(29,29));
//filter_box_v(img3.data, img4.data, width, height, radius);
finish_time = clock();
program_time = (float)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("Program complete time opencv: %f\n", program_time);
imshow("opencv", img2); // 展示图片
waitKey(0); // 获取键盘按键响应
cv::imwrite("im_opencv.png", img2);
//col
img.copyTo(img2);
start_time = clock();
filter_box_fast(r, r2, radiu, height, width);
filter_box_fast(g, g2, radiu, height, width);
filter_box_fast(b, b2, radiu, height, width);
finish_time = clock();
program_time = (float)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("Program complete time col jifen: %f\n", program_time);
merge(rgb2, 3, img2);
imshow("col", img2); // 展示图片
waitKey(0);
cv::imwrite("im_col.png", img2);
//col2
img.copyTo(img2);
start_time = clock();
filter_box_fast2(r, r2, radiu, height, width);
filter_box_fast2(g, g2, radiu, height, width);
filter_box_fast2(b, b2, radiu, height, width);
finish_time = clock();
program_time = (float)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("Program complete time col2 jifen: %f\n", program_time);
merge(rgb2, 3, img2);
imshow("col2", img2); // 展示图片
waitKey(0);
cv::imwrite("im_col2.png", img2);
img.copyTo(img2);
start_time = clock();
filter_box_v3(r, r2, radiu, height, width);
filter_box_v3(g, g2, radiu, height, width);
filter_box_v3(b, b2, radiu, height, width);
finish_time = clock();
program_time = (float)(finish_time - start_time) / CLOCKS_PER_SEC;
printf("Program complete time jifenpoint: %f\n", program_time);
merge(rgb2, 3, img2);
imshow("jifenpoint", img2); // 展示图片
waitKey(0);
cv::imwrite("im_jifenpoint.png", img2);
//imshow("test3", img2); // 展示图片
//waitKey(0); // 获取键盘按键响应
destroyAllWindows(); // 销毁所有窗口
}