2018-01-19 19:49:15 fsx_xiaomei 阅读数 1579
上边两篇博文描述了利用ColorMatrix来处理图片,这篇文章讲如何改变图片的像素点的ARGB值,从而改变图片呈现效果。值得注意的是,我们是不能直接改变传递的原始图片的,一般是根据原始图片生成一张新的图片用来修改。
在Android中,系统提供了Bitmap.getPixels()方法来提取整个Bitmap中的像素点,并保存到第一个数组中,方法如下:
public void getPixels(@ColorInt int[] pixels, int offset, int stride,int x, int y, int width, int height)
//pixels---接收位图颜色值的数组
//offset---写入到pixels[]中的第一个像素索引值(即第一个像素要放在数组的那个位置)
//stride---pixels[]中的行间距
//x---从位图中读取的第一个像素的x坐标值
//y---从位图中读取的第一个像素的y坐标值(x,y确定从哪个像素点开始)
//width---从每一行中读取的像素宽度
//height---读取的行数

通常情况下,可以使用如下代码:
从第(0,0)个位置开始,一次获取原图所有点的像素值,一次放入数组oldArr中,第一个像素点的索引为0;

mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

接下来就是利用代码获取每个像素具体的ARGB值,代码如下:

for (int i = 0; i < oldArr.length; i++) {
    index = oldArr[i];
    oldA = Color.alpha(index);//A:透明度
    oldR = Color.red(index);//R:红
    oldG = Color.green(index);//G:绿
    oldB = Color.blue(index);//B:蓝
}

获取到具体的颜色值后,就可以通过相应的算法修改它的ARGB值,从而得到一个新的像素,从而重构一张新的图像。例如下代码,将修改过的ARGB值合成一个新的像素:

newA = oldA;
newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);
newG = (int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);
newB = (int) (0.272 * oldR + 0.534 * oldG + 0.131 * oldB);
curArr[i] = Color.argb(newA, newR, newG, newB);//重构一个新像素

最后通过如下代码,将处理后的像素点数组重新set给Bitmap

curPic.setPixels(curArr, 0, width, 0, 0, width, height);
  • 常用像素点处理效果
    这些处理方法是某些专业人士发现的,当然我也没查过到底是谁哈。通过特定的算法对每个像素点进行处理,就可以得到不同的处理效果。

  • 底片效果

newR = 255 - oldR;
newG = 255 - oldG;
newB = 255 - oldB;

实现代码:

/**底片效果*/
private Bitmap getNegativePic() {
    int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
    Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);//获取原图的像素值,将像素值放入oldArr中

    for (int i = 0; i < oldArr.length; i++) {
        index = oldArr[i];//依次获取某个像素点
        oldA = Color.alpha(index);//获取相应的ARGB值
        oldR = Color.red(index);
        oldG = Color.green(index);
        oldB = Color.blue(index);

        newA = oldA;
        newR = 255 - oldR;//做相应的处理,生成新的ARGB值
        newG = 255 - oldG;
        newB = 255 - oldB;

        //保证每个新的ARGB值的范围在0~255之间
        newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
        newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
        newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);
        //合成新的像素点,将新的像素点一次放入数组curArr
        curArr[i] = Color.argb(newA, newR, newG, newB);
    }
    //用curArr合成新的图片curPic
    curPic.setPixels(curArr, 0, width, 0, 0, width, height);
    return curPic;
}
  • 老照片效果
newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);
newG = (int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);
newB = (int) (0.272 * oldR + 0.534 * oldG + 0.131 * oldB);
  • 浮雕效果
index = oldArr[i - 1];
oldA = Color.alpha(index);
oldR = Color.red(index);
oldG = Color.green(index);
oldB = Color.blue(index);

index = oldArr[i];
newR = Color.red(index)
newG = Color.green(index);
newB = Color.blue(index);

newR = oldR - newR + 127;
newG = oldG - newG + 127;
newB = oldB - newB + 127;

运行效果:
这里写图片描述
代码:

/**
 * 常用像素点处理效果 获取一张图片的所有像素点 通过改变图片的每一个像素点来达到对应的处理效果 底片效果 老照片效果 浮雕效果
 * @author fanshenxia
 */
public class PixelsEffectActivity extends Activity implements OnClickListener {

    private ImageView mImg;
    private Button mBtnNevigation, mBtnOld, mBtnRelief;
    private Bitmap mBmp;
    private int[] oldArr, curArr;
    private int width, height, index;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_effect_pixels);

        init();
    }

    private void init() {
        mBmp = BitmapFactory.decodeResource(getResources(), R.drawable.boyimg);
        width = mBmp.getWidth();
        height = mBmp.getHeight();
        oldArr = new int[width * height];
        curArr = new int[width * height];

        mImg = findViewById(R.id.img_pixels);
        mBtnNevigation = findViewById(R.id.negative_pixels);
        mBtnOld = findViewById(R.id.old_pixels);
        mBtnRelief = findViewById(R.id.relief_pixels);

        mBtnNevigation.setOnClickListener(this);
        mBtnOld.setOnClickListener(this);
        mBtnRelief.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.negative_pixels:
            mImg.setImageBitmap(getNegativePic());
            break;
        case R.id.old_pixels:
            mImg.setImageBitmap(getOldPic());
            break;
        case R.id.relief_pixels:
            mImg.setImageBitmap(getReliefPic());
            break;
        }
    }

    /**
     * 底片效果
     * 
     * @return
     */
    private Bitmap getNegativePic() {
        int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
        Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

        for (int i = 0; i < oldArr.length; i++) {
            index = oldArr[i];
            oldA = Color.alpha(index);
            oldR = Color.red(index);
            oldG = Color.green(index);
            oldB = Color.blue(index);

            newA = oldA;
            newR = 255 - oldR;
            newG = 255 - oldG;
            newB = 255 - oldB;

            // newA = (newA>255?255:newA)<0?0:(newA>255?255:newA);
            newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
            newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
            newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);

            curArr[i] = Color.argb(newA, newR, newG, newB);
        }

        //将下部分的像素倒置
//      for (int i = oldArr.length / 2; i >= 0; i--) {
//          curArr[oldArr.length - i - 1] = curArr[i];
//      }
//
//      for (int i = height / 2; i < height; i++) {
//          for (int j = 0; j < width / 2; j++) {
//              int index = curArr[i * width + (width - j) - 1];
//              curArr[i * width + (width - j) - 1] = curArr[i * width + j - 1];
//              curArr[i * width + j - 1] = index;
//          }
//      }

        curPic.setPixels(curArr, 0, width, 0, 0, width, height);

        return curPic;
    }

    /**
     * 老照片效果
     * 
     * @return
     */
    private Bitmap getOldPic() {
        int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
        Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

        for (int i = 0; i < oldArr.length; i++) {
            index = oldArr[i];
            oldA = Color.alpha(index);
            oldR = Color.red(index);
            oldG = Color.green(index);
            oldB = Color.blue(index);

            newA = oldA;
            newR = (int) (0.393 * oldR + 0.769 * oldG + 0.189 * oldB);
            newG = (int) (0.349 * oldR + 0.686 * oldG + 0.168 * oldB);
            newB = (int) (0.272 * oldR + 0.534 * oldG + 0.131 * oldB);

            // newA = (newA>255?255:newA)<0?0:(newA>255?255:newA);
            newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
            newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
            newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);

            curArr[i] = Color.argb(newA, newR, newG, newB);
        }
        curPic.setPixels(curArr, 0, width, 0, 0, width, height);

        return curPic;
    }

    /**
     * 浮雕效果
     * 
     * @return
     */
    private Bitmap getReliefPic() {
        int oldA, oldR, oldG, oldB, newA, newR, newG, newB;
        Bitmap curPic = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        mBmp.getPixels(oldArr, 0, width, 0, 0, width, height);

        for (int i = 1; i < oldArr.length; i++) {
            index = oldArr[i - 1];
            oldA = Color.alpha(index);
            oldR = Color.red(index);
            oldG = Color.green(index);
            oldB = Color.blue(index);

            index = oldArr[i];
            newR = Color.red(index);
            newG = Color.green(index);
            newB = Color.blue(index);

            newR = oldR - newR + 127;
            newG = oldG - newG + 127;
            newB = oldB - newB + 127;

            newR = (newR > 255 ? 255 : newR) < 0 ? 0 : (newR > 255 ? 255 : newR);
            newG = (newG > 255 ? 255 : newG) < 0 ? 0 : (newG > 255 ? 255 : newG);
            newB = (newB > 255 ? 255 : newB) < 0 ? 0 : (newB > 255 ? 255 : newB);

            curArr[i] = Color.argb(oldA, newR, newG, newB);
        }
        curPic.setPixels(curArr, 0, width, 0, 0, width, height);

        return curPic;
    }

}

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView 
        android:id="@+id/img_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/boyimg"
        />

    <Button 
        android:id="@+id/old_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="老照片效果"
        />

    <Button 
        android:id="@+id/negative_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="底片效果"
        />


    <Button 
        android:id="@+id/relief_pixels"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="浮雕效果"
        />
</LinearLayout>

上面我注解了一段代码,是我想要将图片的上半部分弄个倒影的景象:

    //将下部分的像素倒置
//      for (int i = oldArr.length / 2; i >= 0; i--) {
//          curArr[oldArr.length - i - 1] = curArr[i];
//      }
//
//      for (int i = height / 2; i < height; i++) {
//          for (int j = 0; j < width / 2; j++) {
//              int index = curArr[i * width + (width - j) - 1];
//              curArr[i * width + (width - j) - 1] = curArr[i * width + j - 1];
//              curArr[i * width + j - 1] = index;
//          }
//      }

运行效果:
这里写图片描述

2017-07-16 21:37:32 webzhuce 阅读数 2580
图像像素值的访问与修改是最常用的一种操作。VTK提供了两种访问图像像素值的访问。

一、直接访问

  第一种方法是直接发访问vtkImageData的数据数组。vtkImageData提供了GetScalarPointer()函数获取数据数组指针,该函数有三种形式:

virtual void* GetScalarPointer(int coordinates[3]);
virtual void* GetScalarPointer(int x, int y, int z);
virtual void* GetScalarPointer();

前两种形式根据给定的像素索引得到指定的像素值,注意返回的是第(x,y,z)个像素值的地址。而第三种形式是返回图像数据数组的头指针,然后根据头指针可以依次访问索引像素。

示例演示

使用GetScalarPointer遍历图像像素。

CMakeLists.txt代码

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(VisitImagePixelDirectlyExample)
FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})
ADD_EXECUTABLE(VisitImagePixelDirectlyExample   VisitImagePixelDirectlyExample.cpp)
TARGET_LINK_LIBRARIES(VisitImagePixelDirectlyExample ${VTK_LIBRARIES})

VisitImagePixelDirectlyExample.cpp文件代码如下:

/**********************************************************************

文件名: VisitImagePixelDirectlyExample.cpp
Copyright (c) 阿Bin先生. All rights reserved.
更多信息请访问: http://blog.csdn.net/webzhuce

**********************************************************************/

#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkBMPReader.h>
#include <vtkImageData.h>

int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkBMPReader> reader =
        vtkSmartPointer<vtkBMPReader>::New();
    //测试图像:E:\TestData\masonry.bmp
    reader->SetFileName("E:\\TestData\\masonry.bmp");
    reader->Update();

    int dims[3];
    reader->GetOutput()->GetDimensions(dims);

    int nbOfComp;
    nbOfComp = reader->GetOutput()->GetNumberOfScalarComponents();

    for(int k=0; k<dims[2]; k++)
    {
        for(int j=0; j<dims[1]; j++)
        {
            for(int i=0; i<dims[0]; i++)
            {
                if(i<100 && j<100)
                {
                    unsigned char * pixel = 
                        (unsigned char *) ( reader->GetOutput()->GetScalarPointer(i, j, k) );
                    *pixel = 0;
                    *(pixel+1) = 0;
                    *(pixel+2) = 0;
                }
            }
        }
    }

    vtkSmartPointer<vtkImageViewer2> imageViewer =
        vtkSmartPointer<vtkImageViewer2>::New();
    imageViewer->SetInputConnection(reader->GetOutputPort());

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    imageViewer->SetupInteractor(renderWindowInteractor);
    imageViewer->Render();
    imageViewer->GetRenderer()->ResetCamera();
    imageViewer->Render();

    imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
    imageViewer->SetSize(640, 480);
    imageViewer->GetRenderWindow()->SetWindowName("VisitImagePixelDirectlyExample");


    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

运行结果:

这里写图片描述

  示例实现了将图像的100*100大小的区域设置为黑色。通过GetScalarPointer(i,j,k)函数获取访问图像像素值。需要注意的是,GetScalarPointer()函数返回的是void*类型,因此需要根据图像的实际类型进行强制转换。示例中将像素数组的头指针类型转换为unsigned char*。
  此外,需要注意的地方:VTK彩色以及矢量图像采用的是如下图所示的像素存储格式:
  
这里写图片描述

  因此在修改RGB图像以及矢量图像像素时,需要根据像素的元组的组分数目来访问。示例中先获得第(i,j,k)个像素的地址也就是R值的地址,然后将地址加1来访问后续G值和B值。如果对像素的元组组分不确定,可以通过函数GetNumberOfScalarComponent()获取,代码如下:

int nbOfComp = reader->GetOutput->GetNumberOfScalarComponent()

二、迭代器访问

  第二种方法是用vtkImageIterator类实现迭代器方法访问图像像素。该类是一个模板类,使用时,需要提供迭代的图像像素类型以及迭代的区域大小。

示例演示

CMakeLists.txt代码

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(VisitImagePixelIterativelyExample)
FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})
ADD_EXECUTABLE(VisitImagePixelIterativelyExampleVisitImagePixelIterativelyExample.cpp)
TARGET_LINK_LIBRARIES(VisitImagePixelIterativelyExample ${VTK_LIBRARIES})

VisitImagePixelIterativelyExample.cpp文件代码如下:

/**********************************************************************

文件名: VisitImagePixelIterativelyExample.cpp
Copyright (c) 阿Bin先生. All rights reserved.
更多信息请访问: http://blog.csdn.net/webzhuce

**********************************************************************/

#include <vtkSmartPointer.h>
#include <vtkImageViewer2.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkBMPReader.h>
#include <vtkImageData.h>
#include <vtkImageIterator.h>


int main(int argc, char* argv[])
{
    vtkSmartPointer<vtkBMPReader> reader =
        vtkSmartPointer<vtkBMPReader>::New();
    //测试图像:E:\\TestData\\masonry.bmp
    reader->SetFileName ( "E:\\TestData\\masonry.bmp" );
    reader->Update();

    int subRegion[6] = {0,100, 0, 100, 0, 0};
    vtkImageIterator<unsigned char> it(reader->GetOutput(), subRegion);

    while(!it.IsAtEnd())
    {
        unsigned char *inSI = it.BeginSpan();
        unsigned char *inSIEnd = it.EndSpan();

        while(inSI != inSIEnd)
        {
            *inSI = 255-*inSI;
            ++inSI;
        }
        it.NextSpan();
    }

    vtkSmartPointer<vtkImageViewer2> imageViewer =
        vtkSmartPointer<vtkImageViewer2>::New();
    imageViewer->SetInputConnection(reader->GetOutputPort());

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    imageViewer->SetupInteractor(renderWindowInteractor);
    imageViewer->Render();
    imageViewer->GetRenderer()->ResetCamera();
    imageViewer->Render();

    imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
    imageViewer->SetSize(640, 480);
    imageViewer->GetRenderWindow()->SetWindowName("VisitImagePixelIterativelyExample");

    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

运行结果:

这里写图片描述

   示例读取了一幅BMP图像,然后定义一个子区域。注意:在定义子区域时,不要超过图像的大小范围。然后根据图像类型unsigned char定义一个图像迭代器it,定义it时有两个参数:一个是要访问的图像,另一个是访问的图像区域。设置完毕,迭代器开始工作第一个while循环是判断迭代器是否结束。进入循环后,对于每一个迭代器it,又存在第二个循环,判断的是当前像素的元组(Tuple)是否迭代完毕。由于VTK中所有类型的图像格式都是vtkImageData,因此每个像素可能是标量,也可能是矢量。因此,每当访问到一个像素时需要迭代当前像素的元组。元组迭代时,inSI = it.BeginSpan()获取第一个组分,inEnd = it.EndSpan()表示组分迭代完毕。

2019-01-21 17:11:41 weixin_41445387 阅读数 92

学图像这几天,其实发现图像没有我们想象的那么高大上,其实通俗理解bgr图像就是三张单色的图像进行加合。而单色的图像其实就是一个二维的数组,在数组中的数组元素代表的就是每个元素点的bgr的值的多少。 

import cv2 as cv
import numpy as np

图像的加减乘除:

图像的加减乘除其实就是每个数组的元素进行加减乘除

加减乘除后返回到np的图像数组中,然后反映出对应的颜色

def add_demo(m1,m2):
    dst = cv.add(m1,m2)
    cv.imshow("add_demo",dst)

def subtract_demo(m1,m2):
    dst = cv.subtract(m1,m2)
    cv.imshow("subtract_demo",dst)

def divide_demo(m1,m2):
    dst = cv.divide(m1, m2)
    cv.imshow("divide_demo", dst)

逻辑运算: 

#逻辑运算
#利用逻辑函数and可以提取出前面inRange()函数捕捉到的颜色
def logic_demo(m1,m2):
    dst =cv.bitwise_and(m1,m2)
    cv.imshow("logic_demo0",dst)
    dst1= cv.bitwise_or(m1, m2)
    cv.imshow("logic_demo1", dst1)
    dst2 = cv.bitwise_xor(m1, m2)
    cv.imshow("logic_demo2", dst2)
    dst3 = cv.bitwise_not(m1)
    cv.imshow("logic_demo3", dst3)

算颜色的均值和方差: 

def others(m1,m2):
    M1 ,dev1=cv.meanStdDev(m1)#均值和方差
    M2 ,dev2=cv.meanStdDev(m2)
    print(M1)
    print(M2)
    print(dev1)
    print(dev2)

 调整对比度和亮度:

#调整对比度 亮度
def contrast_brightness_demo(image,c,b):
    h,w,ch =image.shape
    blank =np.zeros([h,w,ch],image.dtype)
    dst =cv.addWeighted(image,c,blank,1-c,b)
    cv.imshow("con-bri-demo",dst)

函数demo测试:

src1 =cv.imread("C:\\Users\\william\\Pictures\\go.jpg")
src2 =cv.imread("C:\\Users\\william\\Pictures\\gui.jpg")
print(src1.shape)
print(src2.shape)
cv.namedWindow("image1",cv.WINDOW_AUTOSIZE)
cv.imshow("image1",src1)
cv.imshow("image2",src2)
add_demo(src1,src2)
subtract_demo(src1,src2)
multiply_demo(src1,src2)
divide_demo(src1,src2)
logic_demo(src1,src2)
others(src1,src2)
contrast_brightness_demo(src1,1.2,10)
cv.waitKey(0)
cv.destroyAllWindows()

 

2019-01-18 16:18:53 qq_34814092 阅读数 196

Java OpenCV-4.0.0 图像处理17 像素重映射

Java OpenCV-4.0.0 像素重映射(remap)

图像的坐标映射是通过原图像与目标图像之间建立一种映射关系,这种映射关系有两种,一种是计算原图像任意像素在映射后图像的坐标位置,另一种是计算变换后图像任意像素反映射在原图像的坐标位置。

opencv中提供重映射等操作,其中重映射就是把一幅图像中某位置的像素放置到另一个图片指定位置的过程。为了完成映射过程,需要获得一些插值为非整数像素的坐标。对于原图像和目标图像,满足下式:

G(x,y)=f(h(x,y))

G()是目标图像,f()是源图像,而h(x,y)是作用于(x,y)的映射方法函数。

简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去,形成一张新的图像。

package com.xu.image;

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

/**  
 * 
 * @Title: Image.java   
 * @Description: OpenCV-4.0.0 测试文件
 * @Package com.xu.test   
 * @author: xuhyacinth     
 * @date: 2019年7月10日12:13:13   
 * @version: V-1.0.0 
 * @Copyright: 2019 xuhyacinth
 *
 */
public class Image {

	static {
		//在使用OpenCV前必须加载Core.NATIVE_LIBRARY_NAME类,否则会报错
		System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
	}

	public static void main(String[] args) {
		remape(1);
	}

	/**
	 * OpenCV-4.0.0 自定义图像重映射 
	 * <table border="1" cellpadding="8"> 
	 * <tr><th>输入参数</th><th>参数解释</th></tr> 
	 * <tr><td align="center">0</td><td>缩小为原来的1/2</td></tr> 
	 * <tr><td align="center">1</td><td>上下对调(X轴对称)</td></tr> 
	 * <tr><td align="center">2</td><td>左右对调(Y轴对称)</td></tr> 
	 * <tr><td align="center">3</td><td>上下左右对调(XY轴对称)</td></tr> 
	 * <tr><td colspan="2">注:G(x,y)=f(h(x,y)),重映射的Mat必须为8位单通道灰度图片</td></tr> 
	 * </table>
	 * @param type 图片变换方式 (0,1,2,3)
	 * @return: void 
	 * @date: 2019年7月10日 上午12:53:37
	 */
	public static void remape(int type) {
		Mat src = Imgcodecs.imread("C:\\Users\\xuhya\\Pictures\\99.jpg");
		Mat dst=new Mat();
		Mat xmat = new Mat(src.size (),CvType.CV_32FC1);//8位单通道灰度图片
		Mat ymat = new Mat(src.size (),CvType.CV_32FC1);//8位单通道灰度图片
		for (int i = 0, rlen = src.rows(); i < rlen; i++) {
			for (int j = 0, clen = src.cols(); j < clen; j++) {
				switch (type) {
				case 0://0 缩小为原来的1/2
					if (i > clen * 0.25 && i < clen * 0.75 && j > rlen * 0.25 && j < rlen * 0.75)  {
						xmat.put(i,j,2*(j-clen*0.25));
						ymat.put(i,j,2*(i-rlen*0.25));
					} else {
						xmat.put(i,j,255);
						ymat.put(i,j,255);
					}
					break;
				case 1://1 上下对调(X轴对称)
					xmat.put(i,j,j);
					ymat.put(i,j,rlen-i-1);
					break;
				case 2://2 左右对调(Y轴对称)
					xmat.put(i,j,clen-j-1);
					ymat.put(i,j,i);
					break;
				case 3://3 上下左右对调(XY轴对称)
					xmat.put(i,j,clen-j-1);
					ymat.put(i,j,rlen-i-1);
					break;
				default:
					break;
				}
			}
		}
		Imgproc.remap (src,dst,xmat,ymat,Imgproc.CV_BILATERAL,Imgproc.CV_BLUR,new Scalar(0, 0, 0));
		HighGui.imshow("自定义图像重映射", dst);
		HighGui.waitKey(0);
	}

	/**
	 * OpenCV-4.0.0 自定义像素映射
	 * <table border="1" cellpadding="8">
	 * <tr><th>输入参数</th><th>参数解释</th></tr>
	 * <tr><td align="center">1</td><td>上下旋转</td></tr>
	 * <tr><td align="center">2</td><td>左右旋转</td></tr>
	 * </table>
	 * @param type 旋转方向
	 * @return: void
	 * @date: 2019年7月10日 下午12:25:00
	 */
	public static void myRemap(int type) {
		Mat src=Imgcodecs.imread("C:\\Users\\Administrator\\Pictures\\55.jpg");
		Mat dst = new Mat(src.size(), src.type());
		for (int i = 0, rlen = src.rows(); i < rlen; i++) {
			for (int j = 0, clen = src.cols(); j < clen; j++) {
				if (type==1) {
					dst.put(i, j, src.get(rlen-i-1, j).clone());
				}else if (type==2) {
					dst.put(i, j, src.get(i, clen-j-1).clone());
				}
			}
		}
		HighGui.imshow("自定义图像重映射", dst);
		HighGui.waitKey(0);
	}

}


2018-01-09 16:37:13 Hanging_Gardens 阅读数 10720

利用Imgae.open()打开图像,再利用PIL对象进行操作。这样只是简单的处理,一旦操作复杂就比较困难。而像素级的处理与许多复杂操作相关。所以,通常我们在加载完图片后,都是把图片转换成矩阵来进行复杂操作。

一般情况,在pyton中进行数字图像处理,都需要导入这些包:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

打开并转换图像成矩阵,并显示:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('/home/keysen/caffe/examples/images/cat.jpg')) #打开图像并转化为数字矩阵
plt.figure('cat')
plt.imshow(img)
plt.axis('off')
plt.show()

调用numpy中的array()函数就可以将PIL对象转换为数组对象。图片信息:

print (img.shape)
print (img.dtype)
print (img.size)
print (type(img))

output

(360, 480, 3)
uint8
518400
< type ‘numpy.ndarray’ >

如果是RGB图片,那么转换为array之后,就变成了一个rows*cols*channels的三维矩阵,因此,我们可以使用img[i,j,k]来访问像素值。

示例1:打开图片,并随机添加一些椒盐噪声

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('/home/keysen/caffe/examples/images/cat.jpg')) #打开图像并转化为数字矩阵

#随机生成5000个椒盐
rows,cols,dims=img.shape
for i in range(5000):
    x=np.random.randint(0,rows)
    y=np.random.randint(0,cols)
    img[x,y,:]=255

plt.figure("cat_salt")
plt.imshow(img)
plt.axis('off')
plt.show()

output

这里写图片描述

示例2:将图像二值化,像素值大于128的变为1,否则变为0

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
img=np.array(Image.open('/home/keysen/caffe/examples/images/cat.jpg').convert('L')) #打开图像并转化为数字矩阵

rows,cols=img.shape
for i in range(rows):
    for j in range(cols):
        if (img[i,j]<=128):
            img[i,j]=0
        else:
            img[i,j]=1

plt.figure("cat_black&white")
plt.imshow(img,cmap='gray')
plt.axis('off')
plt.show()

output

这里写图片描述

如果要对多个像素点进行操作,可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问该数组的像素值。下面是有关灰度图像的一些例子:

img[i,:] = im[j,:] # 将第 j 行的数值赋值给第 i 行

img[:,i] = 100 # 将第 i 列的所有数值设为 100

img[:100,:50].sum() # 计算前 100 行、前 50 列所有数值的和

img[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列)

img[i].mean() # 第 i 行所有数值的平均值

img[:,-1] # 最后一列

img[-2,:] (or im[-2]) # 倒数第二行
没有更多推荐了,返回首页