目标
本教程包含如下学习内容
- 获取像素值
- 初始化一个像素矩阵
- 学习cv::saturate_cast用法以及应用
- 学习有关像素转换的炫酷的信息
- 通过一个例子进行图像的亮度增强
理论
注 : \color{#1Ff0f0}{注:} 注::
下述内容引用自书籍Computer Vision: Algorithms and Applications。
图像处理
- 通常一个图像操作代表将一个或多个输入图像进行一个函数处理后得到输出图像的过程。
- 图像转换包括:
- 像素点操作
- 邻域操作
像素点操作
- 在这类图像转换处理中,每一个输出像素值仅仅取决于对应的输入像素值(或者是一些全局搜集的参数和信息)。
- 比如亮度调整,对比度调整和颜色修正与转换。
亮度和对比度调整
- 两种常用的像素点处理是乘法和加法:
- 参数α>0 和β 通常被称之为增益与偏置参数。
- 我们可以理解成f(x)作为输出图像的像素,g(x)为输出图像像素。因此上述公式可以简单表达为:
i 和 j 分代表第 i 行和第 j 列
代码
public class Main {
private static byte saturate(double val) {
int iVal = (int) Math.round(val);
iVal = iVal > 255 ? 255 : (iVal < 0 ? 0 : iVal);
return (byte) iVal;
}
public static void main(String[] args) {
System.loadLibrary("libs/"+ Core.NATIVE_LIBRARY_NAME);
String filename = "images/lena.jpg";
Mat img = imread(filename);
Mat dst = Mat.zeros(img.size(),img.type());
double alpha = 2.0;
int beta = -125;
byte[] imageData =new byte[(int) (img.total()*img.channels())];
img.get(0,0,imageData);
byte[] newImageData = new byte[(int) (dst.total() * dst.channels())];
for (int y = 0; y < img.rows(); y++) {
for (int x = 0; x < img.cols(); x++) {
for (int c = 0; c < img.channels(); c++) {
double pixelValue = imageData[(y*img.cols()+x)*img.channels()+c];
pixelValue = pixelValue<0?pixelValue+256:pixelValue;
newImageData[(y*img.cols()+x)*img.channels()+c] = saturate(alpha*pixelValue+beta);
}
}
}
dst.put(0,0,newImageData);
imshow("raw image",img);
imshow("new image",dst);
waitKey();
System.exit(0);
}
}
讲解
- 首先我们用imread方法载入图像
String filename = "images/lena.jpg";
Mat img = imread(filename);
- 下一步,我们需要对载入的图像进行处理转换,并且将转换结果存储到一个新的Mat对象中,我们希望新的Mat对象拥有如下特性:
- 初始化所有像素值为0
- 与原图像拥有相同的大小
Mat dst = Mat.zeros(img.size(),img.type());
- 接下来我们通过Mat::get 方法将图像中像素取出到byte数组,并且利用三个for循环对每一行每一列以及每个颜色通道(B G R)进行遍历,对每个像素进行操作
saturate(alpha * pixelValue + beta);
byte[] imageData =new byte[(int) (img.total()*img.channels())];
img.get(0,0,imageData);
byte[] newImageData = new byte[(int) (dst.total() * dst.channels())];
for (int y = 0; y < img.rows(); y++) {
for (int x = 0; x < img.cols(); x++) {
for (int c = 0; c < img.channels(); c++) {
double pixelValue = imageData[(y*img.cols()+x)*img.channels()+c];
pixelValue = pixelValue<0?pixelValue+256:pixelValue;
newImageData[(y*img.cols()+x)*img.channels()+c] = saturate(alpha*pixelValue+beta);
}
}
}
dst.put(0,0,newImageData);
注 : \color{#1Ff0f0}{注:} 注::
上述代码采用了三层的for循环,其实我们可以通过下面代码简单实现同样功能:
img.convertTo(dst, -1, alpha, beta);
cv::Mat::convertTo 方法针对new_image = aimage + beta*.的操作相当高效,我们主要是为了演示如何获取以及修改每个像素才使用如上的循环。