OpenCV를 이용하고있습니다. 전송 데이터 크기를 줄여야 할 것 같은데 도움이 필요합니다.


라즈베리파이에서 OpenCV를 통해 Mat 객체를 Java Server로 전송하고있습니다.

클라이언트 일부 코드입니다.

Mat 객체를 이미지로 변환하고, 이를 다시 버퍼 이미지로 변환하여 서버로 전송시킵니다. 이 과정에서 Mat의 데이터 크기가 보통 이미지

정도의 크기로 나옵니다.

public static Image toImage(Mat m) {

        // Check if image is grayscale or color
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if (m.channels() > 1) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }

        // Transfer bytes from Mat to BufferedImage
        int bufferSize = m.channels() * m.cols() * m.rows();
        byte[] b = new byte[bufferSize];
        m.get(0, 0, b); // get all the pixels
        BufferedImage image = new BufferedImage(m.cols(), m.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(b, 0, targetPixels, 0, b.length);
        return image;
    }

    public static BufferedImage toBufferedImage(Image img) {
        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }

        // Create a buffered image with transparency
        BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

        // Draw the image on to the buffered image
        Graphics2D bGr = bimage.createGraphics();
        bGr.drawImage(img, 0, 0, null);
        bGr.dispose();

        // Return the buffered image
        return bimage;
    }

    public static void main(String[] args) {
        String serverIp = "192.168.0.9";
        Socket socket = null;

        try 
        {
            // 서버 연결
            socket = new Socket(serverIp, 1492);
            System.out.println("서버에 연결되었습니다.");

            // OutputStream 등록
            OutputStream os = socket.getOutputStream();
            //등록한 OutputStream을 ObjectOutputStream 방식으로 사용합니다.
            DataOutputStream oos;

            oos = new DataOutputStream(os);

            // Register the default camera
            VideoCapture cap = new VideoCapture(0);

            // Check if video capturing is enabled
            if (!cap.isOpened())
                System.exit(-1);

            // Matrix for storing image
            Mat image = new Mat();
            int count = 0;

            try {
                while (true) 
                {
                    System.out.println("while문 카운트 : " + count );
                    cap.read(image);
                    if (!image.empty()) {

                        BufferedImage bimg = toBufferedImage(toImage(image));

                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        ImageIO.write(bimg, "jpg", baos);
                        byte[] imageInByte = baos.toByteArray();
                        oos.writeInt(imageInByte.length); // write length of the
                                                            // imageInByte
                        oos.write(imageInByte); // write the imageInByte

                        //FileSender fs = new FileSender(socket, oos, cap, image, os);
                        //fs.start();
                        baos.close();
                    }

                    else {
                        System.out.println("No captured frame -- camera disconnected");
                    }
                    count ++;
                }

            } catch (Exception e) {
                e.getStackTrace();
            } finally {
                System.out.println("★클라이언트에서 끈남!!");
                oos.close();
                os.close();
                socket.close();
            }

        } 
        catch (Exception e) { e.printStackTrace(); }
    }
}

그리고, 서버는 이 버퍼 이미지를 다시 이미지로 변환하여 이미지 아이콘으로 변경시켜 화면을 계속 뿌려 줌으로써 부드러운 영상정보를 볼 수 있도록 합니다. 이미지

while (true) 
            {
                System.out.println("client accept!");

                is = socket.getInputStream();

                // 등록한 InputStream을 ObjectInputStream방식으로 사용합니다.
                ois = new DataInputStream(is);

                int length = ois.readInt(); // read length of incoming message
                byte[] data = null;

                if (length > 0) {
                    data = new byte[length];
                    ois.readFully(data, 0, data.length); // read the message
                }

                String dirName = "C:\\Users\\안형욱\\workspace\\시스템개발프로젝트1";
                String fileName = "test.jpg";

                System.out.println("data length : " + data.length);
                ByteArrayInputStream bais = new ByteArrayInputStream(data);
                BufferedImage imag = ImageIO.read(bais);
                //ImageIO.write(imag, "jpg", new File(dirName, fileName));

                cm.setCameraView(imag); // 받은 이미지를 변환후 적용

                // 파일 수신 작업 시작
                // FileReceiver fr = new FileReceiver(socket, cm);
                // fr.start();
                bais.close();
            }

근데제가 올린 코드는 일반 PC 노트북의 카메라를 이용할 경우에는 문제없이 부드러운 화면이 잘나오지만, 라즈베리파이를 사용할 경우에는 뚝뚝 끊기듯 나오는 경우가 발생합니다. 이유는 성능 문제라고 생각합니다. 아무래도 라즈베리 파이가 성능이 PC만큼 좋지가 않기때문이라고 생각합니다.

그래서, 본론을 말씀드리자면 OpenCV에서 Mat의 픽셀이나 데이터에 접근을해서 전체적으로 보내는 데이터 크기를 줄여서 보낼 수 있는 방법이 있을까 싶어서 질문드립니다.

만약 이 방법 말고 다른 방법으로 라즈베리파이에서 끊기는 문제는 해결할 수 있는지도 알 수 있으면 좋을것 같습니다. 답변부탁드려요~~~ 꼭!!! ㅠㅠㅠㅠ...!!

코드는 자바로 된 코드로 알려주시면 좋을것 같습니다...! 부탁드립니다..!

  • 2016년 08월 21일에 수정됨
    리눅스(유닉스) 기반의 시스템에서 웹 서비스를 개발하고 있습니다.
  • 2016년 08월 20일에 작성됨

  • 라즈베리 파이에서 영상을 취득해서 서버로 전송하는 것이라면, 영상취득속도 자체가 느릴수도 있을것 같은데... 확인 해보셨나요?    허대영(Daeyoung Heo)   2016.8.23 08:15     
조회수 171


1 답변


OpenCV의 Imgproc.resize() 함수를 이용해서 이미지의 사이즈를 적절하게 줄여보시기 바랍니다. resize() 함수를 사용하는 코드는 아래 링크를 확인해보세요.

OpenCV Imgproc.resize() 함수 설명


로그인이 필요한 기능입니다.

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 작성한 답변에 다른 개발자들이 댓글을 작성하거나 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.
► 로그인
► 계정만들기
Close