最近在做项目,开始接触数字图像处理方面的东西。一时兴起,结合数字图像处理的基本知识和opencv的基本了解,写了一个数字图像处理基本类。类里实现的功能见代码。
环境:vs2008 + opencv
头文件EDIP.h (Enjoy's Digital Image Processing)
class EDIP
{
private:
public:
EDIP();
virtual ~EDIP();
//Sobel算子
//原始图像src 处理后的图像dst 处理方向drt (1、x方向; 2、y方向)
void sobel(const IplImage * src, IplImage * dst, int drt);
//Laplace算子
//原始图像src 处理后的图像dst 掩模方式mode_handle (1、标准模式; 2、对角加强模式)
void laplace(const IplImage * src, IplImage * dst, int mode_handle);
//负片
//原始图像src 处理后的图像dst
void negative_file(const IplImage * src, IplImage * dst);
//标定
//原始图像src 处理后的图像dst
void calibration(long ** t_1, long ** t_2, long ** t_3, int nrow, int ncol);
};
EDIP.cpp
EDIP::EDIP()
{
}
EDIP::~EDIP()
{
}
void EDIP::sobel(const IplImage *src, IplImage *dst, int drt)
{
long sob[3][3] = {0}; //Sobel算子掩模
long ** atemp_1; //临时容器1
long ** atemp_2; //临时容器2
long ** atemp_3; //临时容器3
int h = src->height; //原始图像高度或行数
int w = src->width; //原始图像宽度或列数
//加强x方向边缘的Sobel算子掩模
if (drt == 1)
{
sob[0][0] = -1; sob[0][1] = -2; sob[0][2] = -1;
sob[1][0] = 0; sob[1][1] = 0; sob[1][2] = 0;
sob[2][0] = 1; sob[2][1] = 2; sob[2][2] = 1;
}
//加强y方向边缘的Sobel算子掩模
else if (drt == 2)
{
sob[0][0] = -1; sob[0][1] = 0; sob[0][2] = 1;
sob[1][0] = -2; sob[1][1] = 0; sob[1][2] = 2;
sob[2][0] = -1; sob[2][1] = 0; sob[2][2] = 1;
}
//为临时容器1申请空间,存放原始图片第一个通道的处理结果
atemp_1 = (long **) malloc (h * sizeof(long *));
for (int i = 0; i< h; i++)
atemp_1[i] = (long *) malloc (w * sizeof(long));
//为临时容器2申请空间,存放原始图片第二个通道的处理结果
atemp_2 = (long **) malloc (h * sizeof(long *));
for (int i = 0; i< h; i++)
atemp_2[i] = (long *) malloc (w * sizeof(long));
//为临时容器3申请空间,存放原始图片第三个通道的处理结果
atemp_3 = (long **) malloc (h * sizeof(long *));
for (int i = 0; i< h; i++)
atemp_3[i] = (long *) malloc (w * sizeof(long));
//对原始图像进行Sobel加强
for (int row = 0; row < h; row++)
{
if (row == 0 || row == 1 || row == h-2 || row == h-1)
continue;
for (int col = 0; col < w; col++)
{
if (col == 0 || col == 1 || col == w-2 || col == w-1)
continue;
long temp_1 = 0;
long temp_2 = 0;
long temp_3 = 0;
for (int i = -1; i < 2; i++)
{
uchar * ptr_s = (uchar *)(src->imageData + (row + i) * src->widthStep);
for (int j = -1; j< 2; j++)
{
temp_1 += ptr_s[3 * (col + j)] * sob[i + 1][j + 1];
temp_2 += ptr_s[3 * (col + j) + 1] * sob[i + 1][j + 1];
temp_3 += ptr_s[3 * (col + j) + 2] * sob[i + 1][j + 1];
}
}
atemp_1[row][col] = temp_1;
atemp_2[row][col] = temp_2;
atemp_3[row][col] = temp_3;
}
}
//对临时容器中的处理结果进行标定,使其中值介于[0,255]之间
calibration(atemp_1, atemp_2, atemp_3, h, w);
//将标定后的结果赋给目标变量
for (int row = 0; row < h; row++)
{
uchar * ptr_d = (uchar *)(dst->imageData + row * dst->widthStep);
for (int col = 0; col < w; col++)
{
ptr_d[3 * col] = (uchar)(atemp_1[row][col]);
ptr_d[3 * col + 1] = (uchar)(atemp_2[row][col]);
ptr_d[3 * col + 2] = (uchar)(atemp_3[row][col]);
}
}
//释放临时容器
free(atemp_1);
free(atemp_2);
free(atemp_3);
}
void EDIP::laplace(const IplImage *src, IplImage *dst, int mode_handle)
{
long lap[3][3] = {0}; //Laplace算子3*3掩模
long ** atemp_1; //临时容器1
long ** atemp_2; //临时容器2
long ** atemp_3; //临时容器3
int h = src->height; //原始图像高度或行数
int w = src->width; //原始图像宽度或列数
//标准Laplace算子掩模
if (mode_handle == 1)
{
lap[0][0] = 0; lap[0][1] = 1; lap[0][2] = 0;
lap[1][0] = 1; lap[1][1] = -4; lap[1][2] = 1;
lap[2][0] = 0; lap[2][1] = 1; lap[2][2] = 0;
}
//兼顾对角方向的Laplace算子掩模
else if (mode_handle == 2)
{
lap[0][0] = 1; lap[0][1] = 1; lap[0][2] = 1;
lap[1][0] = 1; lap[1][1] = -8; lap[1][2] = 1;
lap[2][0] = 1; lap[2][1] = 1; lap[2][2] = 1;
}
//为临时容器1申请空间,存放原始图片第一个通道的处理结果
atemp_1 = (long **) malloc (h * sizeof(long *));
for (int i = 0; i< h; i++)
atemp_1[i] = (long *) malloc (w * sizeof(long));
//为临时容器2申请空间,存放原始图片第二个通道的处理结果
atemp_2 = (long **) malloc (h * sizeof(long *));
for (int i = 0; i< h; i++)
atemp_2[i] = (long *) malloc (w * sizeof(long));
//为临时容器3申请空间,存放原始图片第三个通道的处理结果
atemp_3 = (long **) malloc (h * sizeof(long *));
for (int i = 0; i< h; i++)
atemp_3[i] = (long *) malloc (w * sizeof(long));
//对原始图像进行Laplace加强
for (int row = 0; row < h; row++)
{
if (row == 0 || row == 1 || row == h-2 || row == h-1)
continue;
for (int col = 0; col < w; col++)
{
if (col == 0 || col == 1 || col == w-2 || col == w-1)
continue;
long temp_1 = 0;
long temp_2 = 0;
long temp_3 = 0;
for (int i = -1; i < 2; i++)
{
uchar * ptr_s = (uchar *)(src->imageData + (row + i) * src->widthStep);
for (int j = -1; j< 2; j++)
{
temp_1 += ptr_s[3 * (col + j)] * lap[i + 1][j + 1];
temp_2 += ptr_s[3 * (col + j) + 1] * lap[i + 1][j + 1];
temp_3 += ptr_s[3 * (col + j) + 2] * lap[i + 1][j + 1];
}
}
atemp_1[row][col] = temp_1;
atemp_2[row][col] = temp_2;
atemp_3[row][col] = temp_3;
}
}
//对临时容器中的处理结果进行标定,使其中值介于[0,255]之间
calibration(atemp_1, atemp_2, atemp_3, h ,w);
//将标定后的结果赋给目标变量
for (int row = 0; row < h; row++)
{
uchar * ptr_d = (uchar *)(dst->imageData + row * dst->widthStep);
for (int col = 0; col < w; col++)
{
ptr_d[3 * col] = (uchar)(atemp_1[row][col]);
ptr_d[3 * col + 1] = (uchar)(atemp_2[row][col]);
ptr_d[3 * col + 2] = (uchar)(atemp_3[row][col]);
}
}
//释放临时容器
free(atemp_1);
free(atemp_2);
free(atemp_3);
}
void EDIP::negative_file(const IplImage *src, IplImage *dst)
{
int h = src->height; //原始图像高度或行数
int w = src->width; //原始图像宽度或列数
//对原始图像进行负片加强
for (int row = 0; row < h; row++)
{
uchar * ptr_s = (uchar *)(src->imageData + row * src->widthStep);
uchar * ptr_d = (uchar *)(dst->imageData + row * dst->widthStep);
for (int col = 0; col < w; col++)
{
ptr_d[3 * col] = 255 - ptr_s[3 * col];
ptr_d[3 * col + 1] = 255 - ptr_s[3 * col + 1];
ptr_d[3 * col + 2] = 255 - ptr_s[3 * col + 2];
}
}
}
void EDIP::calibration(long **t_1, long **t_2, long **t_3, int nrow, int ncol)
{
long tmax_1 = -1024; //一通道最大值
long tmax_2 = -1024; //二通道最大值
long tmax_3 = -1024; //三通道最大值
long tmin_1 = 1024; //一通道最小值
long tmin_2 = 1024; //二通道最小值
long tmin_3 = 1024; //三通道最小值
//找到各个通道的最小值
for (int row = 0; row < nrow; row++)
{
for (int col = 0; col < ncol; col++)
{
if (t_1[row][col] < tmin_1) tmin_1 = t_1[row][col];
if (t_1[row][col] < tmin_2) tmin_1 = t_2[row][col];
if (t_1[row][col] < tmin_3) tmin_1 = t_3[row][col];
}
}
tmin_1 = abs(tmin_1);
tmin_2 = abs(tmin_2);
tmin_3 = abs(tmin_3);
//各通道的值加上取绝对值后的最小值,将各个通道的最小值标定为0
//找到一次标定后各个通道的最大值
for (int row = 0; row < nrow; row++)
{
for (int col = 0; col < ncol; col++)
{
t_1[row][col] = t_1[row][col] + tmin_1;
if (t_1[row][col] > tmax_1) tmax_1 = t_1[row][col];
t_2[row][col] = t_2[row][col] + tmin_2;
if (t_2[row][col] > tmax_2) tmax_2 = t_2[row][col];
t_3[row][col] = t_3[row][col] + tmin_3;
if (t_3[row][col] > tmax_3) tmax_3 = t_3[row][col];
}
}
//将各个通道的最大值表定位255
for (int row = 0; row < nrow; row++)
{
for (int col = 0; col < ncol; col++)
{
t_1[row][col] = (long)(t_1[row][col] * 255 / tmax_1);
t_2[row][col] = (long)(t_2[row][col] * 255 / tmax_2);
t_3[row][col] = (long)(t_3[row][col] * 255 / tmax_3);
}
}
}
不知道是我理解的有问题还是怎么,Laplace强化处理后,重新标定的结果基色偏黄。
其他功能有待添加