才寫完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
- Fix
OpenCVFrameConverter
error inIPCameraFrameGrabber
(pull #1278) - Allow setting properties for
OpenCVFrameGrabber
andOpenCVFrameRecorder
withsetOption()
(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
一、首先導入公共平臺,然後再導入armhf平臺和windows平臺。
二、導入攝像頭面板控件
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