图像变换可以看作如下:
- 像素变换 – 点操作
- 邻域操作 – 区域
调整图像亮度和对比度属于像素变换-点操作 (图像越亮,颜色值越往255靠近)
公式: g(i,j) = α*f(i,j)+β 其中 α>0, β是增益变量 这里说的是RGB(0-255)格式的图像,所以α要大于0,对于tif格式图像,颜色数据是可以小于零的
对比度: 就是两个像素点之间的差值,差值越大对比度越高,反之越低
vs代码
#include "../common/common.hpp"
void main1_7(int argc, char ** argv)
{
Mat src = imread(getCVImagesPath("images/test1_3.png"), IMREAD_COLOR);
imshow("src", src);
int height = src.rows;
int width = src.cols;
Mat dst = Mat::zeros(src.size(), src.type());
float alpha = 1.2f;
float beta = 10.f;
Mat convert, dst_convert;
src.convertTo(convert, CV_32F);
imshow("convert", convert);//float型的图像显示不出来。。 在java中也无法将float型的Mat转换成bitmap
dst_convert = Mat::zeros(src.size(), src.type());
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("gray", gray);
Mat dst_gray = Mat::zeros(gray.size(), gray.type());
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
uchar b = src.at<Vec3b>(row, col)[0];
uchar g = src.at<Vec3b>(row, col)[1];
uchar r = src.at<Vec3b>(row, col)[2];
dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(alpha*b + beta);//调整对比度与亮度,公式: g(i,j) = α*f(i,j)+β 其中 α>0, β是增益变量
dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(alpha*g + beta);//图像越亮,颜色值越往255靠近
dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(alpha*r + beta);//对比度: 就是两个像素点之间的差值,差值越大对比度越高,反之越低
float f_b = convert.at<Vec3f>(row, col)[0];
float f_g = convert.at<Vec3f>(row, col)[1];
float f_r = convert.at<Vec3f>(row, col)[2];
dst_convert.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(alpha*f_b + beta);//用float计算会比uchar精度高一些,值会大一点点
dst_convert.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(alpha*f_g + beta);
dst_convert.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(alpha*f_r + beta);
uchar v = gray.at<uchar>(row, col);
dst_gray.at<uchar>(row, col) = saturate_cast<uchar>(alpha*v + beta);//灰度图也是一样的计算
}
}
imshow("dst", dst);
imshow("dst_convert", dst_convert);
imshow("dst_gray", dst_gray);
waitKey(0);
}
效果图
android代码
@BindView(R.id.iv_cv1_7_input) ImageView mSrcIv;
@BindView(R.id.iv_cv1_7_output1) ImageView mSrcUcharIv;
@BindView(R.id.iv_cv1_7_output2) ImageView mSrcFloatIv;
@BindView(R.id.iv_cv1_7_output3) ImageView mGrayIv;
@BindView(R.id.iv_cv1_7_output4) ImageView mGrayUcharIv;
private Bitmap mSrcBmp;
private Bitmap mSrcUcharBmp;
private Bitmap mSrcFloatBmp;
private Bitmap mGrayBmp;
private Bitmap mGrayUcharBmp;
private Mat mSrcMat = new Mat();
private Mat mSrcUcharMat;
private Mat mSrcFloatMat;
private Mat mGrayMat = new Mat();
private Mat mGrayUcharMat;
private float alpha = 1.2f;
private float beta = 10.f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cv1_7);
mUnbinder = ButterKnife.bind(this);
//src
mSrcBmp = CV310Utils.getBitmapFromAssets(this, "opencv/test1_3.png");
mSrcIv.setImageBitmap(mSrcBmp);
Utils.bitmapToMat(mSrcBmp, mSrcMat);
initBitmaps(mSrcBmp);
//src uchar
int height = mSrcMat.rows();
int width = mSrcMat.cols();
mSrcUcharMat = Mat.zeros(mSrcMat.size(), mSrcMat.type());
//convert src float
Mat mat = new Mat();//转换成float的Mat
mSrcMat.convertTo(mat, CvType.CV_32F);
mSrcFloatMat = Mat.zeros(mat.size(), mat.type());
//gray
Imgproc.cvtColor(mSrcMat, mGrayMat, Imgproc.COLOR_BGR2GRAY);
CV310Utils.mat2bitmapAndShowInIv(mGrayMat, mGrayBmp, mGrayIv);
mGrayUcharMat = Mat.zeros(mGrayMat.size(), mGrayMat.type());
long start = System.currentTimeMillis();
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
//src uchar
byte rgbaUchar[] = new byte[4];
mSrcMat.get(row, col, rgbaUchar);
byte r = changeContractAndBrightness(rgbaUchar[0]);//调整对比度与亮度,公式: g(i,j) = α*f(i,j)+β 其中 α>0, β是增益变量
byte g = changeContractAndBrightness(rgbaUchar[1]);//图像越亮,颜色值越往255靠近
byte b = changeContractAndBrightness(rgbaUchar[2]);//对比度: 就是两个像素点之间的差值,差值越大对比度越高,反之越低
byte dstUchar[] = {r, g, b, rgbaUchar[3]};
mSrcUcharMat.put(row, col, dstUchar);
//src float
float rgbaFloat[] = new float[4];
mat.get(row, col, rgbaFloat);
float f_r = changeContractAndBrightness(rgbaFloat[0]);//用float计算会比uchar精度高一些,值会大一点点
float f_g = changeContractAndBrightness(rgbaFloat[1]);
float f_b = changeContractAndBrightness(rgbaFloat[2]);
float dstFloat[] = {f_r, f_g, f_b, rgbaFloat[3]};
mSrcFloatMat.put(row, col, dstFloat);
//gray
byte v[] = new byte[1];
mGrayMat.get(row, col, v);
byte pixel[] = new byte[1];
pixel[0] = changeContractAndBrightness(v[0]);
mGrayUcharMat.put(row, col, pixel);//灰度图也是一样的计算
}
}
LogUtils.d("mydebug---", "time="+(System.currentTimeMillis()-start));//4579
CV310Utils.mat2bitmapAndShowInIv(mSrcUcharMat, mSrcUcharBmp, mSrcUcharIv);
Mat convert = new Mat();
mSrcFloatMat.convertTo(convert, CvType.CV_8UC1);//src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4 matToBitmap只支持这几种type转换,所以需要把CV_32F再转成CV_8UC1
CV310Utils.mat2bitmapAndShowInIv(convert, mSrcFloatBmp, mSrcFloatIv);//手机上由于转换的限制,float型的计算出的Mat无法直接显示,只能转成uchar,所以视觉上比ucahr变化不大
CV310Utils.mat2bitmapAndShowInIv(mGrayUcharMat, mGrayUcharBmp, mGrayUcharIv);
}
/*初始化bitmap*/
private void initBitmaps(Bitmap bmp){
mSrcUcharBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mSrcFloatBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mGrayBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
mGrayUcharBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Bitmap.Config.RGB_565);
}
//调整对比度与亮度,公式: g(i,j) = α*f(i,j)+β 其中 α>0, β是增益变量
//图像越亮,颜色值越往255靠近
//对比度: 就是两个像素点之间的差值,差值越大对比度越高,反之越低
private byte changeContractAndBrightness(byte color) {
return (byte) CV310Utils.saturateCastUchar(alpha*CV310Utils.byte2unsignedchar(color) + beta);
}
private float changeContractAndBrightness(float color) {
return CV310Utils.saturateCastUchar(alpha*color + beta);
}
效果图