OpenCV With Java

关于图像

颜色模型

RGB

RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的。

RGBA

RGBA是代表Red(红色) Green(绿色) Blue(蓝色)和 Alpha(透明度或者不透明度)。

HSV

色调(H),饱和度(S),明度(V)

这里写图片描述

灰度图

这里写图片描述

BGR 分层

单通道图片

分层

矩阵(Mat)

资料来源

Mat 创建矩阵

Mat 是Matrix(矩阵)的缩写

Mat 类位于 org.opencv.core 中

最常用的Mat 构造方法:

Mat(int rows, int cols , int type)

rows: 矩阵的行数

cols : 矩阵的列数

type: 矩阵中每个元素的类型

矩阵元素类型

Modifier and TypeField and Description
static intCV_16S
static intCV_16SC1
static intCV_16SC2
static intCV_16SC3
static intCV_16SC4
static intCV_16U
static intCV_16UC1
static intCV_16UC2
static intCV_16UC3
static intCV_16UC4
static intCV_32F
static intCV_32FC1
static intCV_32FC2
static intCV_32FC3
static intCV_32FC4
static intCV_32S
static intCV_32SC1
static intCV_32SC2
static intCV_32SC3
static intCV_32SC4
static intCV_64F
static intCV_64FC1
static intCV_64FC2
static intCV_64FC3
static intCV_64FC4
static intCV_8S
static intCV_8SC1
static intCV_8SC2
static intCV_8SC3
static intCV_8SC4
static intCV_8U
static intCV_8UC1
static intCV_8UC2
static intCV_8UC3
static intCV_8UC4

命名原则:

CV_{U|S|F}C

其中,U是无符号整型,S是有符号整型,F是浮点数,C是通道数

bit-depth 对应位数,有8位,16位,32位,64位可选

number_of_channels是通道数,有1,2,3,4可选

System.loadLibrary

System.loadLibrary是Java的Api,即使用Java的JNI桥接机制去呼叫C/C++。因为Opencv采用C++开发,所以需要利用JNI。因此,在使用Opencv中的方法之前,我们需要 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); 这行代码我们每次使用opencv时都需要使用,因此推荐在main方法所在class的静态块中加入这行代码。

代码

1. 创建 Mat
public class NewMat {

    static{System.loadLibrary(Core.NATIVE_LIBRARY_NAME  );}

    public static void main(String[] args) {
        //Mat 对象的创建
        Mat mat = new Mat(3,3,CvType.CV_8UC1);//3行3列,矩阵元素类型(1个通道,8位无符号)
        mat.put(0, 0, new byte[]{1,2,3,4,5,6,7,8,9});//从0行0列开始设置矩阵中每个元素的值
        System.out.println(mat.dump());//打印矩阵
    }
}
2. 常用方法
public class NewMat2 {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    public static void main(String[] args) {
        // Mat 对象创建
        Mat mat = new Mat(4,3,CvType.CV_8UC1);//4行3列,矩阵元素类型(1个通道,8位无符号)
        mat.put(0, 0, new byte[]{1,2,3,4,5,6,7,8,9,10,11,12});//从0行0列开始设置矩阵中每个元素的值
        System.out.println("矩阵的行数:" + mat.rows());
        System.out.println("矩阵的列数:" + mat.cols());
        System.out.println("矩阵的元素个数:" + mat.total());//矩阵的size,先列后行
        System.out.println("矩阵的Size:" + mat.size());
        System.out.println("矩阵第1行第2列的元素之位:" + mat.get(0, 1)[0]);
        System.out.println(mat.dump());//遍历矩阵
    }
}
3. Mat 的线性代数基础操作
public class LinearAlgebraBasic {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    public static void main(String[] args) {
        Mat m1 = new Mat(2, 2,CvType.CV_32FC1);
        m1.put(0, 0, new float[]{1,2,3,4});
        System.out.println("m1为矩阵:"+ m1.dump());
        System.out.println("m1的转置矩阵为:" + m1.t().dump());//m1.t()为m1的转置矩阵
        System.out.println("m1的逆置矩阵为:"+ m1.inv().dump());//m1.inv()为m1 的逆置矩阵
        Mat m2 = new Mat();
        m2.push_back(m1);//将m1矩阵的所有制放到m2矩阵的后面
        m2.push_back(m1);
        System.out.println("m2是将m1放置到起后两次的结果:"+ m2.dump());

        Mat m3 = Mat.eye(2, 2,CvType.CV_8UC1);//创建的2*2的单位矩阵
        Mat m4 = Mat.ones(2, 2, CvType.CV_8UC1);//创建2*2的全1矩阵
        Mat m5 = Mat.zeros(2, 2, CvType.CV_8UC1);//创建2*2的全0矩阵
        System.out.println("创建单位矩阵:"+ m3.dump());
        System.out.println("创建全1矩阵:" + m4.dump());
        System.out.println("创建全0矩阵:" + m5.dump());
    }
//要计算逆矩阵,矩阵的元素类型必须为CV_32FC1或CV_64FC1
//要计算逆矩阵,矩阵的行数和列数必须相同
//矩阵使用push_back 函数时需要双方式相同的元素类型
}
4. Mat 的线性代数加减乘除操作
public class LinearAlgebraMiddle {

    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void main(String[] args) {
        Mat m1 = new Mat(2, 2, CvType.CV_32FC1);// m1矩阵2行2列,元素类型float
        m1.put(0, 0, new float[] { 1, 2, 3, 4 });

        Mat m2 = m1.clone();// 复制m1给m2,m2与m1一致

        System.out.println("矩阵m1:" + m1.dump());
        System.out.println("矩阵m2:" + m2.dump());

        // 矩阵加法
        Mat m3 = new Mat();
        Core.add(m1, m2, m3);// m1与m2相加,赋给m3
        System.out.println("m1与m2相加:" + m3.dump());

        //矩阵减法
        Mat m4 = new Mat();
        Core.subtract(m1, m2, m4);//m1与m2相减,赋给m4
        System.out.println("m1与m2相减:"+m4.dump());

        //矩阵乘法
        Mat m5 = new Mat();
        Core.gemm(m1, m2, 1, new Mat(), 0, m5);
        System.out.println("m1与m2相乘:"+ m5.dump());
// 矩阵乘法:Core.gemm(src1, src2, alpha, src3, beta, dst);
// 参数说明:
//      src1:src1:第一个输入矩阵,元素类型必须是float或double
//      src2:第2个输入矩阵,元素类型与src1要相同
//      alpha:权重值
//      src3:第三个可有可无的矩阵
//      beta:权重值
//      dst:计算乘法结果之后的输出矩阵,元素类型与src1要相同
// 原理:dst=alpha*src1*src2+beta*src3
    }
}
5. 图片的读写操作
public class ReadAndWriteImage {

    static{System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    public static void main(String[] args) {

        Mat source = Imgcodecs.imread("E://3.jpg");//读取图像,参数为图像的存储路径
        System.out.println("channels="+source.channels());//灰度图=1,RGB=3
        Imgcodecs.imwrite("E://t.jpg", source);//存储图像,参数1为要存储的路径,参数2位要存储的Mat对象
//      3.jpg为已有图像,t.jpg为新写入的图像
//      Imgcodecs.imread支持OpenCV3.0以上版本使用
//      OpenCV 2.4.x  需使用Highgui.imread来进行替代。
//      imwrite也是一样的。
    }
}
6. 工具类: mat2BufferedImage
public class mat2BufferedImage {

    public static BufferedImage matToBufferedImage(Mat matrix){
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int) matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch(matrix.channels()){
        case 1:
            type=BufferedImage.TYPE_BYTE_GRAY;
            break;
        case 3:
            type = BufferedImage.TYPE_3BYTE_BGR;
            //bgr to rgb
            byte b;
            for (int i = 0; i < data.length; i = i + 3) {
                b = data[i];
                data[i] = data[i + 2];
                data[i + 2] = b;
            }
            break;
        default:
            return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }
}
7. 在窗体中显示图像
public class ShowImage {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    //Swing 使用的是Eclipse的 WindowsBuilder 插件创建的
    private JFrame frame;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ShowImage window = new ShowImage();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public ShowImage() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 800, 450);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        JLabel lblNewLabel = new JLabel();
        lblNewLabel.setBounds(0, 0, 800, 450);
        frame.getContentPane().add(lblNewLabel);

        Mat source = Imgcodecs.imread("E://3.jpg");//加载图像为Mat格式
        /* 使用工具类: mat2BufferedImage 将 OpenCV中的 Mat 转换为Swing 中的
         * BufferedImage 格式,因为Swing中只支持BufferedImage格式图像显示。
         */
        BufferedImage image = mat2BufferedImage.matToBufferedImage(source);
        lblNewLabel.setIcon(new ImageIcon(image));
    }
}
8. 读取摄像头并显示
public class CameraBasic {

    static{System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    private JFrame frame;

    static JLabel label;

    static int flag = 0;//类静态变量,用于控制按下按钮后,停止摄像头的读取

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    CameraBasic window = new CameraBasic();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        //TODO 操作
        VideoCapture camera = new VideoCapture();
        camera.open(0);//open函数中的0代表当前计算机中索引为0的摄像头,如果你的计算机有多个摄像头,那么依次1,2,3...
        if(!camera.isOpened()){
            System.out.println("Camera Error");//如果摄像头调用失败,输出错误信息
        } else {
            Mat frame = new Mat();//创建一个输出帧
            while(flag == 0){
                camera.read(frame);//read方法读取摄像头的当前帧
                label.setIcon(new ImageIcon(mat2BufferedImage
                        .matToBufferedImage(frame)));
                try {
                    Thread.sleep(100);//线程暂停 100ms
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            /* 这段代码取消注释后的作用:拍照功能,存到E盘下
             * if(flag == 1){
                Imgcodecs.imwrite("E://"+new Date().getTime()+".jpg", frame);
            }*/
        }
    }

    /**
     * Create the application.
     */
    public CameraBasic() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 700, 450);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        label = new JLabel("");
        label.setBounds(0, 0, 684, 412);
        frame.getContentPane().add(label);

        JButton button = new JButton("拍照");
        //TODO 设置监听
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                flag=1;//静态变量设置为1,从而按下按钮是会停止摄像头的调用
            }
        });
        button.setBounds(26, 24, 93, 23);
        frame.getContentPane().add(button);
    }
}
9. 读取视频并显示
public class VideoPlay {

    static{System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    private JFrame frame;
    private static JLabel lblNewLabel;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    VideoPlay window = new VideoPlay();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        //TODO 操作
        /**
         * 运行之前,要先把 build/bin 里的opencv_ffmpeg341_64.dll复制到c:windows/system32目录下
         * 或者把 bin目录添加到环境变量 path 中
         */
        VideoCapture capture = new VideoCapture("E://1.mp4");//读取视频
        if(!capture.isOpened()){
            System.out.println("Error");
        } else {
            Mat webcam_image = new Mat();
            capture.read(webcam_image);
            while(true) {
                capture.read(webcam_image);
                if(!webcam_image.empty()){
                    BufferedImage b = mat2BufferedImage.matToBufferedImage(webcam_image);
                    lblNewLabel.setIcon(new ImageIcon(b));
                } else{
                    System.out.println("视频已结束");
                    capture.release();
                    break;
                }
            }
        }   
    }

    /**
     * Create the application.
     */
    public VideoPlay() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        lblNewLabel = new JLabel();
        lblNewLabel.setBounds(0, 0, 434, 262);
        frame.getContentPane().add(lblNewLabel);
    }
}
10. 彩色图像转成灰度图像
public class RgbtoGRayTest {

    static {System.loadLibrary(Core.NATIVE_LIBRARY_NAME);}

    private JFrame frame;

    Mat mrgb;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    RgbtoGRayTest window = new RgbtoGRayTest();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public RgbtoGRayTest() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(0, 0, 800, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        JLabel lblNewLabel = new JLabel();
        lblNewLabel.setBounds(0, 50, 500, 400);
        frame.getContentPane().add(lblNewLabel);

        JButton button = new JButton("灰度化");
        //TODO 按按钮后把图片进行灰度化
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                Mat mgray = new Mat(mrgb.rows(),mrgb.cols(),mrgb.type());//新建一个Mat矩阵,行列和类型和与图片的一致
                Imgproc.cvtColor(mrgb, mgray, Imgproc.COLOR_RGB2GRAY);//opencv中彩色转灰度的函数
                //mgray = MyRgbtoGray.rgbToGray(mrgb);//自己实现的彩图转成灰度图像的方法
                lblNewLabel.setIcon(new ImageIcon(mat2BufferedImage.matToBufferedImage(mgray)));
            }
        });
        button.setBounds(0, 0, 93, 23);
        frame.getContentPane().add(button);

        //TODO 将图片放入窗口 
        mrgb = Imgcodecs.imread("E://3.jpg", Imgcodecs.CV_LOAD_IMAGE_COLOR);
        lblNewLabel.setIcon(new ImageIcon(mat2BufferedImage.matToBufferedImage(mrgb)));
    }
}
11. 自己实现的彩图转灰度图像的方法
/**
 * 自己实现的彩图转灰度图像的方法
 *
 */
public class MyRgbtoGray {

    public static Mat rgbToGray(Mat mrgb){
        Mat mgray = new Mat(mrgb.rows(),mrgb.cols(),CvType.CV_8UC1);
        for(int i = 0;i<mrgb.rows();i++){
            for(int j = 0; j < mrgb.cols(); j++){
                double[] value = mrgb.get(i, j);//顺序为 BGR
                double valueGray=0.114*value[0] + 0.587*value[1] + 0.2989*value[2];//转换算法
                mgray.put(i, j, valueGray);
            }
        }
        return mgray;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值