【樹莓派】使用JavaCV1.5.3調用攝像頭,自寫的攝像頭控件

才寫完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 in IPCameraFrameGrabber (pull #1278)
  • Allow setting properties for 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 

一、首先導入公共平臺,然後再導入armhf平臺和windows平臺。

Netbeans 8.5導入
Netbeans 8.2 項目導入

二、導入攝像頭面板控件

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章