常用的像素操作算法:Resize、Flip、Rotate

简介: 常用的像素操作算法:Resize、Flip、Rotate

Resize



图像缩放是把原图像按照目标尺寸放大或者缩小,是图像处理的一种。


图像缩放有多种算法。最为简单的是最临近插值算法,它是根据原图像和目标图像的尺寸,计算缩放的比例,然后根据缩放比例计算目标像素所依据的原像素,过程中自然会产生小数,这时就采用四舍五入,取与这个点最相近的点。


除此之外,还有双线性插值算法。


双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。


其公式如下:


f(i+u,j+v) =(1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)


其中U和V表示浮点坐标的小数部分,显然离目标点距离越近的点的权重越大,这也正符合目标点的值与离他最近的点最接近这一事实。


cv4j的resize目前支持这两种算法。通过Resize类的源码,可以看到有两个常量

public final static int NEAREST_INTEPOLATE = 1; // 最临近插值算法
    public final static int BILINE_INTEPOLATE = 2;     // 双线性插值算法


使用最临近插值算法,将原图缩小到0.75倍。

CV4JImage cv4jImage = new CV4JImage(bitmap);
        ImageProcessor imageProcessor = cv4jImage.getProcessor();
        Resize resize = new Resize(0.75f);
        imageProcessor = resize.resize(imageProcessor,Resize.NEAREST_INTEPOLATE);
        if (imageProcessor!=null) {
            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
            result1.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
        }


使用双线性插值算法,将原图放大2倍。

cv4jImage = new CV4JImage(bitmap);
        ImageProcessor imageProcessor2 = cv4jImage.getProcessor();
        resize = new Resize(2f);
        imageProcessor2 = resize.resize(imageProcessor,Resize.BILINE_INTEPOLATE);
        if (imageProcessor2!=null) {
            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor2.getWidth(), imageProcessor2.getHeight(), imageProcessor2.getPixels());
            result2.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
        }


效果如下:


image.png

图像缩放.png


Flip



Flip是翻转的意思,也被称为镜像变换。又可以分为水平镜像和垂直镜像,水平镜像即将图像左半部分和右半部分以图像竖直中轴线为中心轴进行兑换,而竖直镜像则是将图像上半部分和下半部分以图像水平中轴线为中心轴进行兑换。


flip的算法很简单

public final static int FLIP_VERTICAL = -1;
    public final static int FLIP_HORIZONTAL = 1;
    public static void flip(ImageProcessor processor, int option) {
        int width = processor.getWidth();
        int height = processor.getHeight();
        int ch = processor.getChannels();
        int index1 = 0;
        int index2 = 0;
        int total = width*height;
        byte[][] output = new byte[ch][total];
        for(int row=0; row<height; row++) {
            for(int col=0; col<width; col++) {
                index1 = row*width+col;
                if(option == FLIP_HORIZONTAL) {
                    index2 = row*width + width-col-1;
                } else if(option == FLIP_VERTICAL){
                    index2 = (height-row-1)*width + col;
                } else {
                    throw new CV4JException("invalid option : " + option);
                }
                for(int i=0; i<ch; i++) {
                    output[i][index2] = processor.toByte(i)[index1];
                }
            }
        }
        if(ch == 3) {
            ((ColorProcessor) processor).putRGB(output[0], output[1], output[2]);
        } else {
            ((ByteProcessor) processor).putGray(output[0]);
        }
    }


实现具体的左右翻转

CV4JImage cv4jImage = new CV4JImage(bitmap);
        ImageProcessor imageProcessor = cv4jImage.getProcessor();
        Flip.flip(imageProcessor,Flip.FLIP_HORIZONTAL);
        if (imageProcessor!=null) {
            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
            result1.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
        }


实现具体的上下翻转

cv4jImage = new CV4JImage(bitmap);
        ImageProcessor imageProcessor2 = cv4jImage.getProcessor();
        Flip.flip(imageProcessor2,Flip.FLIP_VERTICAL);
        if (imageProcessor2!=null) {
            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor2.getWidth(), imageProcessor2.getHeight(), imageProcessor2.getPixels());
            result2.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
        }


效果如下:


image.png

图像翻转.png


Rotate



图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。当然这个点通常就是图像的中心。既然是按照中心旋转,自然会有这样一个属性:旋转前和旋转后的点离中心的位置不变。


图像的旋转是图像几何变换的一种,旋转前后的图像的像素的RGB都是没有改变的,改变的只是每一个像素的所在位置。


cv4j提供两种旋转的算法:NormRotate和FastRotate

下面以NormRotate为例,使用起来很简单,旋转120度,背景为红色。

CV4JImage cv4jImage = new CV4JImage(bitmap);
        ImageProcessor imageProcessor = cv4jImage.getProcessor();
        NormRotate normRotate = new NormRotate();
        imageProcessor = normRotate.rotate(imageProcessor,120, Scalar.rgb(255,0,0));
        if (imageProcessor!=null) {
            CV4JImage resultCV4JImage = new CV4JImage(imageProcessor.getWidth(), imageProcessor.getHeight(), imageProcessor.getPixels());
            result.setImageBitmap(resultCV4JImage.getProcessor().getImage().toBitmap());
        }


效果如下:


image.png

图像旋转.png


总结



cv4jgloomyfish和我一起开发的图像处理库,纯java实现,我们已经分离了一个Android版本和一个Java版本。


像素操作是 cv4j 的基本功能之一,本文介绍了三种常见的变换。我们可以通过图像的Resize、Flip、Rotate变换来丰富图片数据的多样性。

相关文章
|
6月前
|
机器学习/深度学习 存储 算法
【算法基础】常数操作 时间复杂度 选择排序 冒泡排序 插入排序 位运算
【算法基础】常数操作 时间复杂度 选择排序 冒泡排序 插入排序 位运算
|
5月前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
89 10
|
5月前
|
算法 计算机视觉
图像处理之线性插值旋转算法(biline-interpolation rotate algorithm)
图像处理之线性插值旋转算法(biline-interpolation rotate algorithm)
51 0
|
5月前
|
算法
数据结构和算法学习记录——二叉搜索树的插入操作、删除操作
数据结构和算法学习记录——二叉搜索树的插入操作、删除操作
32 0
|
5月前
|
算法
数据结构和算法学习记录——认识二叉搜索树及二叉搜索树的查找操作(递归以及迭代实现-查找操作、查找最大和最小元素)
数据结构和算法学习记录——认识二叉搜索树及二叉搜索树的查找操作(递归以及迭代实现-查找操作、查找最大和最小元素)
50 0
|
6月前
|
机器学习/深度学习 人工智能 运维
人工智能平台PAI 操作报错合集之请问Alink的算法中的序列异常检测组件,是对数据进行分组后分别在每个组中执行异常检测,而不是将数据看作时序数据进行异常检测吧
阿里云人工智能平台PAI (Platform for Artificial Intelligence) 是阿里云推出的一套全面、易用的机器学习和深度学习平台,旨在帮助企业、开发者和数据科学家快速构建、训练、部署和管理人工智能模型。在使用阿里云人工智能平台PAI进行操作时,可能会遇到各种类型的错误。以下列举了一些常见的报错情况及其可能的原因和解决方法。
|
6月前
|
算法 测试技术 C++
【数论】【分类讨论】【C++算法】1611使整数变为 0 的最少操作次数
【数论】【分类讨论】【C++算法】1611使整数变为 0 的最少操作次数
|
6月前
|
算法 定位技术 Python
ArcGIS中ArcMap栅格重采样操作与算法选择
ArcGIS中ArcMap栅格重采样操作与算法选择
201 1
|
11月前
|
算法 测试技术 C#
C++二分算法:得到子序列的最少操作次数
C++二分算法:得到子序列的最少操作次数
|
11月前
|
算法 测试技术 C#
C++算法: 最大化数组末位元素的最少操作次数
C++算法: 最大化数组末位元素的最少操作次数