关于图像
颜色模型
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 Type | Field and Description |
|---|---|
| static int | CV_16S |
| static int | CV_16SC1 |
| static int | CV_16SC2 |
| static int | CV_16SC3 |
| static int | CV_16SC4 |
| static int | CV_16U |
| static int | CV_16UC1 |
| static int | CV_16UC2 |
| static int | CV_16UC3 |
| static int | CV_16UC4 |
| static int | CV_32F |
| static int | CV_32FC1 |
| static int | CV_32FC2 |
| static int | CV_32FC3 |
| static int | CV_32FC4 |
| static int | CV_32S |
| static int | CV_32SC1 |
| static int | CV_32SC2 |
| static int | CV_32SC3 |
| static int | CV_32SC4 |
| static int | CV_64F |
| static int | CV_64FC1 |
| static int | CV_64FC2 |
| static int | CV_64FC3 |
| static int | CV_64FC4 |
| static int | CV_8S |
| static int | CV_8SC1 |
| static int | CV_8SC2 |
| static int | CV_8SC3 |
| static int | CV_8SC4 |
| static int | CV_8U |
| static int | CV_8UC1 |
| static int | CV_8UC2 |
| static int | CV_8UC3 |
| static int | CV_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;
}
}
7097

被折叠的 条评论
为什么被折叠?



