才写完1.5.2没多久,昨天,bytedeco发布了JavaCV1.5.3。再跟一把风。再升级下控件。
其实1.5.3也没升太多,就是更新到OpenCV 4.3.0,没涉及到和摄像头方面的东西,只用摄像头1.5.2都够用了。
因为1.5.2修复了两个摄像头相关的事情。传送门:https://github.com/bytedeco/javacv/releases
OpenCVFrameConverter
error in IPCameraFrameGrabber
(pull #1278)OpenCVFrameGrabber
and OpenCVFrameRecorder
with setOption()
(issue #1269)包括下载、使用等、JAVACV1.5.2版本看传送门https://blog.csdn.net/ap114/article/details/105250320,在此不过多赘述。
我的树莓派是3B+ Buster。其他版本pi没试过,理论上同一个系统不会有太大偏差。
我使用的摄像头是USB摄像头,淘宝20块那种,咸鱼10多块也可以捡捡漏,usb摄像头吃cpu。
csi摄像头没试过,对帧率和分辨率有需求的话,用csi摄像头最好。
如果csi摄像头不行烦请在此留言。
这次把1.5.3的各个平台给分开了,每个平台一个文件夹,方便OpenCV小白快速找到自己想要的东西。
项目打包至末尾链接,如发现项目代码和本文代码不同,请以本文为准。
1.5.3分类各平台打包下载:链接:https://pan.baidu.com/s/13dmmxWPABY3w_BuuUPvGfQ 提取码:zgzf
package rpi_javacv_camera;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_videoio.VideoCapture;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.javacv.FrameGrabber.Exception;
import org.bytedeco.javacv.OpenCVFrameGrabber;
/**
*树莓派摄像头OpenCV1.5.3面板组件
*原贴地址:https://blog.csdn.net/ap114/article/details/105531743
* @author 钟离彧
*/
public class CameraJPanel extends JPanel{
//摄像头打开关闭标志
public boolean open = false;
//摄像头暂停标志
private boolean pause = false;
//摄像头画板
private final Canvas canvas = new Canvas();
//当前帧是否绘制完成的锁,若不加锁会造成阻塞
private boolean isDrawfinish = false;
//通过OpenCVFrameGrabber方式过得每帧图像
private OpenCVFrameGrabber grabber;
//通过VideoCapture方式过得每帧图像
private VideoCapture capture;
//OpenCV_VideoCapture格式转换Java图像格式
private final Java2DFrameConverter java2dFrameConverter = new Java2DFrameConverter();
//OpenCV_OpenCVFrameGrabber格式转换Java图像格式
private static OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
//当前每帧的图像
private BufferedImage bufferedImage = null;
//通过Opencv方式的摄像头获取到的帧
private Mat mat = new Mat();
//不停读取摄像头并刷新画板数据的后台线程
private Thread refreshCanvasThread;
//读取方式0=VideoCapture方式读摄像头,1=OpenCVFrameGrabber方式
private int readType = 0;
private int deviceNumber = 0;
private String deviceStr = "";
JLabel lb_img = new JLabel();
public CameraJPanel(JPanel parent,int deviceNumber){
this(parent);
this.deviceNumber = deviceNumber;
}
public CameraJPanel(JPanel parent){
this.setBounds(0, 0, parent.getWidth(), parent.getHeight());
initOpenCV();
}
public CameraJPanel(JPanel parent,int deviceNumber,int readType){
this(parent);
this.deviceNumber = deviceNumber;
if(readType!=0 && readType!=1)readType=0;
this.readType = readType;
initOpenCV();
}
//例如:/dev/video0
public CameraJPanel(JPanel parent,String deviceStr){
this(parent);
this.deviceStr = deviceStr;
}
public CameraJPanel(){
this.setBounds(0, 0, 640, 480);
initOpenCV();
}
public CameraJPanel(int width,int height){
this.setBounds(0, 0, width, height);
initOpenCV();
}
private void initOpenCV(){
canvas.setBounds(0, 0, this.getWidth(), this.getHeight());
lb_img.setBounds(0, 0, this.getWidth(), this.getHeight());
lb_img.setVisible(false);
this.add(canvas);
}
//打开摄像头
public void openCamera(){
this.remove(lb_img);
if(open)return;
this.pause = false;
this.open = true;
canvas.setVisible(true);
if("".equals(deviceStr)){
if(readType == 0){
capture = new VideoCapture(deviceNumber);
}else if(readType == 1){
grabber = new OpenCVFrameGrabber(deviceNumber);
try {
grabber.start(); //开始获取摄像头数据
} catch (Exception ex) {
System.out.println(ex.getMessage());
return;
}
}
}else{
if(readType == 0){
capture = new VideoCapture(deviceStr);
}else if(readType == 1){
grabber = new OpenCVFrameGrabber(deviceStr);
try {
grabber.start(); //开始获取摄像头数据
} catch (Exception ex) {
System.out.println(ex.getMessage());
return;
}
}
}
//设置刷新画板线程
refreshCanvasThread = new Thread(){
public void run() {
while(open){
while(pause)thread_sleep(1);//发现暂停锁,进入暂停
//画板绘图是否完成标志
isDrawfinish = false;
//跨线程更新UI
SwingUtilities.invokeLater(() -> {
if(open && readType == 0){
getImageByVideoCapture();
}else{
getImageByOpenCVFrameGrabber();
}
isDrawfinish = true;
});
//上次的绘图没有完成就不允许继续读取摄像头
while(!isDrawfinish)thread_sleep(1);
}
}
};
refreshCanvasThread.start();
}
//暂停绘画,但不会停止摄像头
public void pauseCamera(){
this.remove(lb_img);
this.pause = true;
}
//继续绘画
public void continueCamera(){
this.remove(lb_img);
this.pause = false;
canvas.setVisible(true);
}
//关闭摄像头
public void closeCamera(){
if(!open)return;
//this.remove(canvas);
this.pause = false;
this.open = false;
if(readType == 0){
capture.close();
}else if(readType == 1){
try {
grabber.stop();
grabber.close();
grabber.release();
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
//清除画板
public void clearCanvas(Color c){
this.remove(lb_img);
canvas.getGraphics().setColor(c);
canvas.getGraphics().fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
//清除画板
public void clearCanvas(){
this.remove(lb_img);
canvas.getGraphics().clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
//通过VideoCapture获取当前帧
public BufferedImage getImageByVideoCapture(){
boolean have = capture.read(mat);
bufferedImage = null;
if(have){
Frame convertFrame2 = converter.convert(mat);
bufferedImage= java2dFrameConverter.convert(convertFrame2);
Image newimage = bufferedImage.getScaledInstance(getWidth(), getHeight(), Image.SCALE_FAST);
canvas.getGraphics().drawImage(newimage, 0, 0,null);
}
return bufferedImage;
}
//通过OpenCVFrameGrabber获取当前帧
public BufferedImage getImageByOpenCVFrameGrabber(){
bufferedImage = null;
try {
if(this.open==false)return null;
Frame convertFrame2 = grabber.grabFrame();
bufferedImage= java2dFrameConverter.convert(convertFrame2);
Image newimage = bufferedImage.getScaledInstance(getWidth(), getHeight(), Image.SCALE_FAST);
canvas.getGraphics().drawImage(newimage, 0, 0,null);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
return bufferedImage;
}
//保存当前帧,默认路径/img/时间戳.png
public String saveImage(){
if(!open)return "";
String currenttime = System.currentTimeMillis() + ".png";
String savepath = getImgPath() + currenttime;
//一个奇怪的BUG,通过上行代码获取当前运行路径会以/开头,例如"/C:/img/1.png"
if(savepath.charAt(0) == '/'){
savepath = savepath.substring(1, savepath.length());
}
saveImage(savepath);
return currenttime;
}
//保存当前帧
public String saveImage(String path) {
try {
boolean isSave = false;
if(readType==1)mat = converter.convertToMat(grabber.grabFrame());
isSave = opencv_imgcodecs.imwrite(path, mat);
if(isSave == false)path=""; //保存失败返回空
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
System.out.println(path);
return path;
}
//重新设置图片
public void setImage(String imgname){
pauseCamera();
this.add(lb_img);
String savepath = imgname;
Image image = new ImageIcon(savepath).getImage();
image = image.getScaledInstance(getWidth(), getHeight(), Image.SCALE_FAST);
lb_img.setIcon(new ImageIcon(image));
lb_img.setVisible(true);
canvas.setVisible(false);
}
//工具方法,线程延迟
private void thread_sleep(int time){
try {
Thread.sleep(time);//time毫秒刷新一次图像
} catch (InterruptedException ex) {
System.out.println(ex.getMessage());
}
}
//工具方法,获取当前运行路径
public static String getRunPath(){
String path = "";
File directory = new File("");//设定为当前文件夹
try{
// System.out.println(directory.getCanonicalPath());//获取标准的路径
// System.out.println(directory.getAbsolutePath());//获取绝对路径
path = directory.getAbsolutePath();
}catch(java.lang.Exception e){}
return path;
}
//工具方法,获取当前图片路径
public static String getImgPath(){
String path = "";
path+=getRunPath()+"\\img\\";
return path;
}
}
Netbeans 8.2 项目打包:https://download.csdn.net/download/ap114/12329651