常用的像素操作算法:图像加法、像素混合、提取图像中的ROI

图像可以是看成是一个多维的数组。读取一张图片,可以看成是读入了一系列的像素内容。这些像素内容,按照不同的模式具有不同的格式。对于三通道的 RGB 位图来说,每个像素是一个 8-bit 整数的三元组。图像的像素操作是比较基础的图像算法,下面列举三个常用的像素操作算法。

图像加法

图像的加法表示两个输入图像在同一位置上的像素相加,得到一个输出图像的过程。

  
  
  1.        imageProcessor = Operator.add(imageProcessor1,imageProcessor2);

  2.        if (imageProcessor!=null) {

  3.            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());

  4.            result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());

  5.        }


Operator的add表示矩阵加法,有一个要求两个图像必须大小一致。

  
  
  1.    public static ImageProcessor add(ImageProcessor image1, ImageProcessor image2) {

  2.        if(!checkParams(image1, image2)) {

  3.            return null;

  4.        }

  5.        int channels = image1.getChannels();

  6.        int w = image1.getWidth();

  7.        int h = image1.getHeight();

  8.        ImageProcessor dst = (channels == 3) ? new ColorProcessor(w, h) : new ByteProcessor(w, h);

  9.        int size = w*h;

  10.        int a=0, b=0;

  11.        int c=0;

  12.        for(int i=0; i<size; i++) {

  13.            for(int n=0; n<channels; n++) {

  14.                a = image1.toByte(n)[i]&0xff;

  15.                b = image2.toByte(n)[i]&0xff;

  16.                c = Tools.clamp(a + b);

  17.                dst.toByte(n)[i] = (byte)c;

  18.            }

  19.        }

  20.        return dst;

  21.    }

在实际工作中,可以通过一张原图和一个mask图像来相加合成一些不规则的效果图片。

像素混合

在这里混合是线性混合,跟之前的图像加法有一定的区别。

  
  
  1.        imageProcessor = Operator.addWeight(imageProcessor1,2.0f,imageProcessor2,1.0f,4);

  2.        if (imageProcessor!=null) {

  3.            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());

  4.            result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());

  5.        }


Operator的addWeight方法表示像素混合。


  
  
  1.    public static ImageProcessor addWeight(ImageProcessor image1, float w1, ImageProcessor image2, float w2, int gamma) {

  2.        if(!checkParams(image1, image2)) {

  3.            return null;

  4.        }

  5.        int channels = image1.getChannels();

  6.        int w = image1.getWidth();

  7.        int h = image1.getHeight();

  8.        ImageProcessor dst = (channels == 3) ? new ColorProcessor(w, h) : new ByteProcessor(w, h);

  9.        int size = w*h;

  10.        int a=0, b=0;

  11.        int c=0;

  12.        for(int i=0; i<size; i++) {

  13.            for(int n=0; n<channels; n++) {

  14.                a = image1.toByte(n)[i]&0xff;

  15.                b = image2.toByte(n)[i]&0xff;

  16.                c = (int)(a*w1 + b*w2 + gamma);

  17.                dst.toByte(n)[i] = (byte)Tools.clamp(c);

  18.            }

  19.        }

  20.        return dst;

  21.    }

提取图像中的ROI

ROI(region of interest),表示图像中感兴趣的区域。对于一张图像,可能我们只对图像中某部分感兴趣,或者要对目标进行跟踪时,需要选取目标特征,所以要提取图像的感兴趣区域。

  
  
  1.        Resources res = getResources();

  2.        final Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.pixel_test_3);

  3.        image.setImageBitmap(bitmap);

  4.        CV4JImage cv4jImage = new CV4JImage(bitmap);

  5.        ImageProcessor imageProcessor = cv4jImage.getProcessor();

  6.        Rect rect = new Rect();

  7.        rect.x = 300;

  8.        rect.y = 200;

  9.        rect.width = 300;

  10.        rect.height = 450;

  11.        ImageProcessor resultImageProcessor = null;

  12.        try {

  13.            resultImageProcessor = Operator.subImage(imageProcessor,rect);

  14.        } catch (CV4JException e) {

  15.        }

  16.        if (resultImageProcessor!=null) {

  17.            CV4JImage resultCV4JImage = new CV4JImage(resultImageProcessor.getWidth(), resultImageProcessor.getHeight(), resultImageProcessor.getPixels());

  18.            result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());

  19.        }



其中,rect.x和rect.y表示ROI的起始点,rect.width和rect.height表示ROI的宽和高。Operator的subImage()表示从原图中提取ROI,之所以在这里还用到了try catch,是为了防止出现ROI的宽度或者高度过大,从而导致数组越界。

subImage方法的代码也很简单

  
  
  1.    /**

  2.     * ROI sub image by rect.x, rect.y, rect.width, rect.height

  3.     * @param image

  4.     * @param rect

  5.     * @return

  6.     * @throws CV4JException

  7.     */

  8.    public static ImageProcessor subImage(ImageProcessor image, Rect rect) throws CV4JException{

  9.        int channels = image.getChannels();

  10.        int w = rect.width;

  11.        int h = rect.height;

  12.        ImageProcessor dst = (channels == 3) ? new ColorProcessor(w, h) : new ByteProcessor(w, h);

  13.        int a=0;

  14.        int index = 0;

  15.        try {

  16.            for(int n=0; n<channels; n++) {

  17.                for(int row=rect.y; row < (rect.y+rect.height); row++) {

  18.                    for(int col=rect.x; col < (rect.x+rect.width); col++) {

  19.                        index = row*image.getWidth() + col;

  20.                        a = image.toByte(n)[index]&0xff;

  21.                        index = (row - rect.y)*w + (col - rect.x);

  22.                        dst.toByte(n)[index] = (byte)a;

  23.                    }

  24.                }

  25.            }

  26.        } catch (ArrayIndexOutOfBoundsException e) {

  27.            throw new CV4JException("数组越界了");

  28.        }

  29.        return dst;

  30.    }

总结

cv4j (https://github.com/imageprocessor/cv4j)是gloomyfish (http://blog.csdn.net/jia20003)和我一起开发的图像处理库,纯java实现,目前还处于早期的版本。

像素操作是 cv4j 的基本功能之一,所有的像素操作算法都在Operator类中。除了本文介绍的三个算法之外,还有substract表示矩阵减法、multiple表示矩阵逐元素乘法、division表示矩阵逐元素除法以及bitwiseand、bitwisenot、bitwiseor、bitwisexor表示每个元素进行位运算分别是和、非、或、异或。

如果您想看该系列先前的文章可以访问下面的文集:http://www.jianshu.com/nb/10401400


关注【Java与Android技术栈】

更多精彩内容请关注扫码


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值