图像的点运算就是对图像中的每一个像素点进行计算,为像素点和像素点之间的运算。函数表示形式为 :B(x,y)=f[A(x,y)],其中f为映射函数。点运算有时候被称为灰度变换。
1. 线性点运算
线性点运算的函数形式可用线性方程来描述,即:
G(i,j)=T[f(i,j)]=af(i,j)+b
当a>1 时,输出图像的对比度增大;a<1时对比度减小。
当a=1,把!=0时,图像仅亮度发生变化。
当a=-1,b=255时,输出图像的灰度会反转。
以下为C++代码的实现。
Mat LinearPointOperation(Mat& src, double a, double b) { Mat dst(src.rows, src.cols, src.type(),Scalar(0)); if (src.channels() == 3) { for (int i = 0; i < src.rows; i++) for (int j = 0; j < src.cols; j++) { uchar *p = src.ptr<uchar>(i, j); uchar *pdst = dst.ptr<uchar>(i, j); int ans0 = int(p[0] * a + b); int ans1 = int(p[1] * a + b); int ans2 = int(p[2] * a + b); pdst[0] = ans0 > 255 ? 255 : (ans0 >0 ? ans0 : 0); pdst[1] = ans1 > 255 ? 255 : (ans1 >0 ? ans1 : 0); pdst[2] = ans2 > 255 ? 255 : (ans2 >0 ? ans2 : 0); } } else if (src.channels() == 1) { for (int i = 0; i < src.rows; i++) { uchar *srcRow = src.ptr(i); uchar *dstRow = dst.ptr(i); for (int j = 0; j < src.cols; j++) { int ans0 = int(srcRow[j] * a + b); dstRow[j] = ans0 > 255 ? 255 : (ans0 > 0? ans0 : 0); } } } return dst; }
当a=2,b=-100时,效果图如下:
当a=-1,b=255时:
2. 对数变换
s=clog(1+r)
其中,c是一个常数,,假设r≥0,根据上图中的对数函数的曲线可以看出:对数变换,将源图像中范围较窄的低灰度值映射到范围较宽的灰度区间,同时将范围较宽的高灰度值区间映射为较窄的灰度区间,从而扩展了暗像素的值,压缩了高灰度的值,能够对图像中低灰度细节进行增强。;从函数曲线也可以看出,反对数函数的曲线和对数的曲线是对称的,在应用到图像变换其结果是相反的,反对数变换的作用是压缩灰度值较低的区间,扩展高灰度值的区间。
基于OpenCV的实现,其对数变换的代码如下:
//图像的对数变换 out=c*log(1+src)/log(v) v是对数变换的底数
Mat LogOperation(Mat& src,double c,double v) { float logArr[256]; for (int i = 0; i < 256; i++) { logArr[i] = c * log(i / 255.0 + 1.0) / log(v); logArr[i] = logArr[i] > 1 ? 1 : logArr[i]; } Mat dst(src.size(), CV_32FC3); for (int i = 0; i < src.rows; i++) for (int j = 0; j < src.cols; j++) { uchar *p = src.ptr<uchar>(i, j); float *pdst = dst.ptr<float>(i, j); pdst[0] = logArr[p[0]]; pdst[1] = logArr[p[1]]; pdst[2] = logArr[p[2]]; } return MatFloatToChar(dst); }
在c=1,v=1.5的情况下:
3. 伽马变换
伽马变换又称指数变换或幂变换,公式:out=c*(src+e)^r
r>1, 较亮的区域灰度被拉伸,较暗的区域灰度被压缩的更暗,图像整体变暗;
r<1, 较亮的区域灰度被压缩,较暗的区域灰度被拉伸的较亮,图像整体变亮;
代码实现如下:
//图像的伽马变换 out=c*(src+e)^r r是伽马变换的指数,e是补偿系数
Mat GamarOperation(Mat& src, double c, double e,double r) { Mat dst(src.size(), CV_32FC3); Mat img = MatCharToFloat(src); for (int i = 0; i < img.rows; i++) for (int j = 0; j < img.cols; j++) { float *p = img.ptr<float>(i, j); float *pdst = dst.ptr<float>(i, j); float ans0 = c * pow((p[0]) + e, r); float ans1 = c * pow((p[1]) + e, r); float ans2 = c * pow((p[2]) + e, r); pdst[0] = ans0>1?1:ans0; pdst[1] = ans1>1?1:ans1; pdst[2] = ans2>1?1:ans2; } return MatFloatToChar(dst); }
当c=1 e=0 r=0.5时效果图如下: