05_OpenCv图像线性混合

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gzx110304/article/details/88858328

05_OpenCv图像线性混合

一.图像的线性混合

  • dst = alpha*src1 + beta*src2
  • beta = 1-alpha
  • alpha的取值为:0.01.0之间,同理,beta取值也在0.01.0之间
  • gama不取零的情况:dst = alphasrc1 + betasrc2 + gama

二.Opencv Android SDK中图像线性混合的API

Core.addWeighted(src1, alpha, src2, beta, gama, dst);

三.通过遍历Mat实现图像线性混合

//1.将Bitmap对象转化为Mat对象
Mat srcMat1 = new Mat();
Mat srcMat2 = new Mat();
Utils.bitmapToMat(src1, srcMat1);
Utils.bitmapToMat(src2, srcMat2);

//2.只有srcMat1和srcMat2的size和type都相同时才能实现混合
if(srcMat1.cols() != srcMat2.cols() || srcMat1.rows() != srcMat2.rows() || srcMat1.type() != srcMat2.type()) {
    throw new RuntimeException("can not blend image src1 and src2");
}

//3.通过Mat对象的cols()方法和rows()方法,获取图片的宽高
int width = srcMat1.cols();
int height = srcMat1.rows();
//4.获取图片的通道数
int cnum = srcMat1.channels();
Log.d(TAG, cnum + "");
//5.分配一个数组,其长度为图片的通道数
byte[] src1Bgra = new byte[cnum];
byte[] src2Bgra = new byte[cnum];
byte[] dstBgra = new byte[cnum];

//6.循环遍历Mat对象的对应行列上的像素信息
Mat dst = new Mat(srcMat1.size(), srcMat1.type());
for(int row=0; row<height; row++) {
    for(int col=0; col<width; col++) {
        //7.取出对应行列上的像素信息,赋给字节数组
        srcMat1.get(row, col, src1Bgra);
        srcMat2.get(row, col, src2Bgra);
        //8.对图片的每一个通道进行混合
        for(int i=0; i<cnum; i++) {
            dstBgra[i] = (byte) (alpha*(src1Bgra[i]&0xff) + beta*(src2Bgra[i]&0xff) + gama);
        }
        //9.将取反后的像素重新设置回Mat对象
        dst.put(row, col, dstBgra);
    }
}
//10.将像素取反后的Mat对象转换为Bitmap对象
Utils.matToBitmap(dst, dstBitmap);

//11.释放Mat对象
dst.release();
srcMat1.release();
srcMat2.release();

四.通过遍历Bitmap实现图像线性混合

int width = src1.getWidth();
int height = src1.getHeight();

//只有src1的宽度与src2的宽度相等并且src1的高度与src2的高度相等,才能实现图像混合
if(src1.getWidth() != src2.getWidth() || src1.getHeight() != src2.getHeight()) {
    throw new RuntimeException("can not blend image src1 and src2");
}

//1.开辟像素缓冲区(int数组),其长度为(bitmap的宽度 * bitmap的高度)
int[] pixels1 = new int[width * height];
int[] pixels2 = new int[width * height];
int[] pixels3 = new int[width * height];
//2.将所有像素取到缓冲区中
src1.getPixels(pixels1, 0, width, 0, 0, width, height);
src2.getPixels(pixels2, 0, width, 0, 0, width, height);
//3.通过pixel遍历每一个像素,并对两个图像进行混合
int src1A = 0, src1R = 0, src1G = 0, src1B = 0, src2A = 0, src2R = 0, src2G = 0, src2B = 0, dstA = 0, dstR = 0, dstG = 0, dstB = 0;
for(int i=0; i<pixels1.length; i++) {
    int pixel1 = pixels1[i];
    int pixel2 = pixels2[i];
    src1A = (pixel1 >> 24) & 0xff;
    src1R = (pixel1 >> 16) & 0xff;
    src1G = (pixel1 >> 8) & 0xff;
    src1B = pixel1 & 0xff;

    src2A = (pixel2 >> 24) & 0xff;
    src2R = (pixel2 >> 16) & 0xff;
    src2G = (pixel2 >> 8) & 0xff;
    src2B = pixel2 & 0xff;

    dstA = (int)(src1A * alpha + src2A * beta + gama);
    dstR = (int)(src1R * alpha + src2R * beta + gama);
    dstG = (int)(src1G * alpha + src2G * beta + gama);
    dstB = (int)(src1B * alpha + src2B * beta + gama);

    int pixel3 = ((dstA&0xff) << 24) | ((dstR&0xff) << 16) | ((dstG&0xff) << 8) | (dstB&0xff);
    pixels3[i] = pixel3;
}
//注意:在android中通过Bitmap去操作像素的时候,必须保证Bitmap对象的isMutable属性为true,否则抛出java.lang.IllegalStateException
dstBitmap.setPixels(pixels3, 0, width, 0, 0, width, height);

五.通过Opencv接口实现图像线性混合

//1.将Bitmap对象转化为Mat对象
Mat srcMat1 = new Mat();
Mat srcMat2 = new Mat();
Utils.bitmapToMat(src1, srcMat1);
Utils.bitmapToMat(src2, srcMat2);

//只有srcMat1和srcMat2的size和type都相同时才能实现混合
if(srcMat1.cols() != srcMat2.cols() || srcMat1.rows() != srcMat2.rows() || srcMat1.type() != srcMat2.type()) {
    throw new RuntimeException("can not blend image src1 and src2");
}
//2.通过OpenCv接口实现图像混合
Mat dst = new Mat(srcMat1.size(), srcMat1.type());
Core.addWeighted(srcMat1, alpha, srcMat2, beta, gama, dst);
Utils.matToBitmap(dst, dstBitmap);

//3.释放Mat对象
dst.release();
srcMat1.release();
srcMat2.release();

六.结果(alpha=0.5, beta=0.5, gama=0.0)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/gzx110304/article/details/88858328
今日推荐