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

Resize

圖像縮放是把原圖像按照目標尺寸放大或者縮小,是圖像處理的一種。

圖像縮放有多種算法。最為簡單的是最臨近插值算法,它是根據(jù)原圖像和目標圖像的尺寸,計算縮放的比例,然后根據(jù)縮放比例計算目標像素所依據(jù)的原像素,過程中自然會產(chǎn)生小數(shù),這時就采用四舍五入,取與這個點最相近的點。

除此之外,還有雙線性插值算法。

雙線性插值,又稱為雙線性內(nèi)插。在數(shù)學上,雙線性插值是有兩個變量的插值函數(shù)的線性插值擴展,其核心思想是在兩個方向分別進行一次線性插值。

其公式如下:
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表示浮點坐標的小數(shù)部分,顯然離目標點距離越近的點的權(quán)重越大,這也正符合目標點的值與離他最近的點最接近這一事實。

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());
        }

效果如下:


圖像縮放.png

Flip

Flip是翻轉(zhuǎn)的意思,也被稱為鏡像變換。又可以分為水平鏡像和垂直鏡像,水平鏡像即將圖像左半部分和右半部分以圖像豎直中軸線為中心軸進行兌換,而豎直鏡像則是將圖像上半部分和下半部分以圖像水平中軸線為中心軸進行兌換。

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]);
        }
    }

實現(xiàn)具體的左右翻轉(zhuǎn)

        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());
        }

實現(xiàn)具體的上下翻轉(zhuǎn)

        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());
        }

效果如下:


圖像翻轉(zhuǎn).png

Rotate

圖像旋轉(zhuǎn)是指圖像以某一點為中心旋轉(zhuǎn)一定的角度,形成一幅新的圖像的過程。當然這個點通常就是圖像的中心。既然是按照中心旋轉(zhuǎn),自然會有這樣一個屬性:旋轉(zhuǎn)前和旋轉(zhuǎn)后的點離中心的位置不變。

圖像的旋轉(zhuǎn)是圖像幾何變換的一種,旋轉(zhuǎn)前后的圖像的像素的RGB都是沒有改變的,改變的只是每一個像素的所在位置。

cv4j提供兩種旋轉(zhuǎn)的算法:NormRotate和FastRotate

下面以NormRotate為例,使用起來很簡單,旋轉(zhuǎn)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());
        }

效果如下:


圖像旋轉(zhuǎn).png

總結(jié)

cv4jgloomyfish和我一起開發(fā)的圖像處理庫,純java實現(xiàn),我們已經(jīng)分離了一個Android版本和一個Java版本。

像素操作是 cv4j 的基本功能之一,本文介紹了三種常見的變換。我們可以通過圖像的Resize、Flip、Rotate變換來豐富圖片數(shù)據(jù)的多樣性。

如果您想看該系列先前的文章可以訪問下面的文集:
http://www.itdecent.cn/nb/10401400

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容