Потоковая передача с IP-камеры с использованием OpenCV

Я использую OpenCV для обработки изображения с камеры, однако на данный момент я использую веб-камеру USB, подключенную к моему компьютеру. Мне было интересно, можно ли внести изменения в мой текущий код для потоковой передачи видео с IP-адреса.

startCamera метод открывает камеру.

Код:

public class ObjRecognitionController {
// FXML camera button
@FXML
private Button cameraButton;
// the FXML area for showing the current frame
@FXML
private ImageView originalFrame;
// the FXML area for showing the mask
@FXML
private ImageView maskImage;
// the FXML area for showing the output of the morphological operations
@FXML
private ImageView morphImage;
// FXML slider for setting HSV ranges
@FXML
private Slider hueStart;
@FXML
private Slider hueStop;
@FXML
private Slider saturationStart;
@FXML
private Slider saturationStop;
@FXML
private Slider valueStart;
@FXML
private Slider valueStop;
// FXML label to show the current values set with the sliders
@FXML
private Label hsvCurrentValues;

// a timer for acquiring the video stream
private ScheduledExecutorService timer;
// the OpenCV object that performs the video capture
private VideoCapture capture = new VideoCapture();
// a flag to change the button behavior
private boolean cameraActive;

// property for object binding
private ObjectProperty<String> hsvValuesProp;

/**
 * The action triggered by pushing the button on the GUI
 */
@FXML
private void startCamera()
{
    // bind a text property with the string containing the current range of
    // HSV values for object detection
    hsvValuesProp = new SimpleObjectProperty<>();
    this.hsvCurrentValues.textProperty().bind(hsvValuesProp);

    // set a fixed width for all the image to show and preserve image ratio
    this.imageViewProperties(this.originalFrame, 400);
    this.imageViewProperties(this.maskImage, 200);
    this.imageViewProperties(this.morphImage, 200);

    if (!this.cameraActive) {
        // start the video capture
        this.capture.open(0);

        // is the video stream available?
        if (this.capture.isOpened()) {
            this.cameraActive = true;

            // grab a frame every 33 ms (30 frames/sec)
            Runnable frameGrabber = new Runnable() {

                @Override
                public void run() {
                    Image imageToShow = grabFrame();
                    originalFrame.setImage(imageToShow);
                }
            };

            this.timer = Executors.newSingleThreadScheduledExecutor();
            this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);

            // update the button content
            this.cameraButton.setText("Stop Camera");
        } else {
            // log the error
            System.err.println("Failed to open the camera connection...");
        }
    } else {
        // the camera is not active at this point
        this.cameraActive = false;
        // update again the button content
        this.cameraButton.setText("Start Camera");

        // stop the timer
        try {
            this.timer.shutdown();
            this.timer.awaitTermination(33, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            // log the exception
            System.err.println("Exception in stopping the frame capture, trying to release the camera now... " + e);
        }

        // release the camera
        this.capture.release();
    }
}

/**
 * Get a frame from the opened video stream (if any)
 * 
 * @return the {@link Image} to show
 */
private Image grabFrame()
{
    // init everything
    Image imageToShow = null;
    Mat frame = new Mat();

    // check if the capture is open
    if (this.capture.isOpened())
    {
        try
        {
            // read the current frame
            this.capture.read(frame);

            // if the frame is not empty, process it
            if (!frame.empty())
            {
                // init
                Mat blurredImage = new Mat();
                Mat hsvImage = new Mat();
                Mat mask = new Mat();
                Mat morphOutput = new Mat();

                // remove some noise
                Imgproc.blur(frame, blurredImage, new Size(7, 7));

                // convert the frame to HSV
                Imgproc.cvtColor(blurredImage, hsvImage, Imgproc.COLOR_BGR2HSV);

                // get thresholding values from the UI
                // remember: H ranges 0-180, S and V range 0-255
                Scalar minValues = new Scalar(this.hueStart.getValue(), this.saturationStart.getValue(),
                        this.valueStart.getValue());
                Scalar maxValues = new Scalar(this.hueStop.getValue(), this.saturationStop.getValue(),
                        this.valueStop.getValue());

                // show the current selected HSV range
                String valuesToPrint = "Hue range: " + minValues.val[0] + "-" + maxValues.val[0]
                        + "\tSaturation range: " + minValues.val[1] + "-" + maxValues.val[1] + "\tValue range: "
                        + minValues.val[2] + "-" + maxValues.val[2];
                this.onFXThread(this.hsvValuesProp, valuesToPrint);

                // threshold HSV image to select tennis balls
                Core.inRange(hsvImage, minValues, maxValues, mask);
                // show the partial output
                this.onFXThread(this.maskImage.imageProperty(), this.mat2Image(mask));

                // morphological operators
                // dilate with large element, erode with small ones
                Mat dilateElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(24, 24));
                Mat erodeElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(12, 12));

                Imgproc.erode(mask, morphOutput, erodeElement);
                Imgproc.erode(mask, morphOutput, erodeElement);

                Imgproc.dilate(mask, morphOutput, dilateElement);
                Imgproc.dilate(mask, morphOutput, dilateElement);

                // show the partial output
                this.onFXThread(this.morphImage.imageProperty(), this.mat2Image(morphOutput));

                // find the tennis ball(s) contours and show them
                frame = this.findAndDrawBalls(morphOutput, frame);

                // convert the Mat object (OpenCV) to Image (JavaFX)
                imageToShow = mat2Image(frame);
            }

        }
        catch (Exception e)
        {
            // log the (full) error
            System.err.print("ERROR");
            e.printStackTrace();
        }
    }

    return imageToShow;
}

/**
 * Given a binary image containing one or more closed surfaces, use it as a
 * mask to find and highlight the objects contours
 * 
 * @param maskedImage
 *            the binary image to be used as a mask
 * @param frame
 *            the original {@link Mat} image to be used for drawing the
 *            objects contours
 * @return the {@link Mat} image with the objects contours framed
 */
private Mat findAndDrawBalls(Mat maskedImage, Mat frame) {
    // init
    List<MatOfPoint> contours = new ArrayList<>();
    Mat hierarchy = new Mat();
    // find contours
    Imgproc.findContours(maskedImage, contours, hierarchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE);

    // if any contour exist...
    if (hierarchy.size().height > 0 && hierarchy.size().width > 0) {
        // for each contour, display it in yellow
        for (int idx = 0; idx >= 0; idx = (int) hierarchy.get(0, idx)[0]) {
            Imgproc.drawContours(frame, contours, idx, new Scalar(0, 255, 255),2);

            Rect rect = Imgproc.boundingRect(contours.get(idx));

            if(rect.x < 25){
                System.out.println("Turn left " + rect.x);
            }else if(rect.x > 600){
                System.out.println("Turn Right: " + rect.x);
            }
            System.out.println();
        }
    }

    return frame;
}

/**
 * Set typical {@link ImageView} properties: a fixed width and the
 * information to preserve the original image ration
 * 
 * @param image
 *            the {@link ImageView} to use
 * @param dimension
 *            the width of the image to set
 */
private void imageViewProperties(ImageView image, int dimension) {
    // set a fixed width for the given ImageView
    image.setFitWidth(dimension);
    // preserve the image ratio
    image.setPreserveRatio(true);
}

/**
 * Convert a {@link Mat} object (OpenCV) in the corresponding {@link Image}
 * for JavaFX
 * 
 * @param frame
 *            the {@link Mat} representing the current frame
 * @return the {@link Image} to show
 */
private Image mat2Image(Mat frame) {
    // create a temporary buffer
    MatOfByte buffer = new MatOfByte();
    // encode the frame in the buffer, according to the PNG format
    Imgcodecs.imencode(".png", frame, buffer);
    // build and return an Image created from the image encoded in the
    // buffer
    return new Image(new ByteArrayInputStream(buffer.toArray()));
}

/**
 * Generic method for putting element running on a non-JavaFX thread on the
 * JavaFX thread, to properly update the UI
 * 
 * @param property
 *            a {@link ObjectProperty}
 * @param value
 *            the value to set for the given {@link ObjectProperty}
 */
private <T> void onFXThread(final ObjectProperty<T> property, final T value)
{
    Platform.runLater(new Runnable() {

        @Override
        public void run()
        {
            property.set(value);
        }
    });
}

}

Документация к камере

VLC Media Player VLC Media Player - это кроссплатформенный видеоплеер, потоковый сервер и преобразователь в одном пакете. Получи это здесь.

Для использования IP-веб-камеры с медиаплеером VLC в ее меню выберите Медиа ⇨ Открыть сетевой поток и введите http://192.168.1.8:8080/video для потокового видео или http://192.168.1.8:8080/audio.wav для потоковой передачи аудио.

Вы также можете использовать VLC Media player для записи видео:

Выберите Медиа -> Конвертировать / Сохранить. Выберите вкладку «Сеть». Введите http://192.168.1.8:8080/video в качестве URL-адреса. Нажмите «Конвертировать / сохранить» Выбрать место назначения файл, формат, в котором вы хотите сохранить, и все готово ZoneMinder Используйте эту конфигурацию:

Общие: Тип источника: Удаленный Функция: Монитор

Источник: Протокол: HTTP Метод: Простое имя хоста: 192.168.1.8 Порт: 8080 Путь удаленного хоста: / видео (просто «видео» не работает).

Примечание. При необходимости укажите свое имя пользователя в пароле в URL-адресе, например: имя пользователя: пароль@192.168.1.8.

Blue Iris Как обычно, откройте диалоговое окно "Добавить камеру".

При использовании IP-веб-камеры вы должны выбрать «MJPEG Stream» из списка вместо конкретной камеры.

Путь к видео: / video Путь к аудио: /audio.wav Имя хоста: 192.168.1.8 Порт: 8080 Неважно, что вы вводите в поле «RTSP / видеопорт».

webcamXP В главном интерфейсе webcamXP щелкните правой кнопкой мыши источник видео и выберите Сетевые камеры ⇨ Подключить ...

Установите марку камеры на Android и модель камеры на IP-веб-камеру. Выберите желаемую предустановку (рекомендуется MJPEG). Нажмите "Далее.

Установите имя хоста на 192.168.1.8 и порт на 8080.

Нажмите ОК, и вы готовы использовать новую камеру!

Дополнительно Вот список URL-адресов службы IP-веб-камеры:

http://192.168.1.8:8080/video - это URL-адрес MJPEG. http://192.168.1.8:8080/shot.jpg получает последний кадр. http://192.168.1.8:8080/audio.wav - аудиопоток в формате Wav. http://192.168.1.8:8080/audio.aac - аудиопоток в формате AAC ( если поддерживается оборудованием). http://192.168.1.8:8080/audio.opus - это аудиопоток в формате Opus. http://192.168.1.8:8080/focus фокусирует камеру. http://192.168.1.8:8080/nofocus освобождает фокус.


person PRCube    schedule 11.03.2016    source источник


Ответы (2)


Вы можете просто изменить

VideoCapture camera = new VideoCapture("IPADDRESS");

or

capture.open("IPADRESS");
person Adah    schedule 11.03.2016
comment
Я использовал 192.168.1.8:8080, но, к сожалению, мне не удалось открыть соединение камеры ... ошибка. Я могу получить доступ к камере из браузера. - person PRCube; 11.03.2016
comment
попробуйте VideoCapture camera = new VideoCapture("http://<username:password>@<ip_address>/video.cgi?.mjpg"; - person Adah; 11.03.2016

Вы должны захватить видео с URL-адреса потока камеры, например

VideoCapture capture = new VideoCapture(url);

URL может быть

url = "http://IPADDRESS:PORT/?dummy=param.mjpg"
//or
url= "http://IPADDRESS:PORT/mjpeg.cgi";
//or
url = "http://IPADDRESS:PORT/mjpg/mjpeg.cgi";
//or
url ="http://IPADDRESS:PORT/video.mjpeg";

Попытайтесь подтвердить правильные значения с помощью вашего браузера, надеюсь, что это поможет.

Также вместо использования приложения IP-веб-камеры с OpenCV, если вы используете устройство Android, лучшей альтернативой является использование приложения droidcam и программного обеспечения для ПК для распознавания веб-камеры, например

VideoCapture capture = new VideoCapture(camIndex);
person Collins Abitekaniza    schedule 11.03.2016
comment
Ничего из этого не работает. Когда я открываю его через браузер, мне нужно только ввести 192.168.1.8:8080. - person PRCube; 11.03.2016
comment
теперь попробуйте скопировать полный URL-адрес, предоставленный браузером, URL-адрес должен заканчиваться на .mjpeg, .cgi, .mjpg, etc в зависимости от камеры. - person Collins Abitekaniza; 11.03.2016
comment
url не имеет расширения, это просто 192.168.1.8:8080, которое напрямую копируется с URL-адреса. бар. Я обнаружил, что он предоставляет специальный URL-адрес для проигрывателя VLC, который является 192.168.1.8:8080/video и он отлично работает с VLC, но не работает с моим кодом. - person PRCube; 11.03.2016
comment
Вы пытались прочитать руководство по настройке своей IP-камеры, там должна быть ссылка на поток - person Collins Abitekaniza; 11.03.2016
comment
Я использую устройство Android и приложение, которое предоставляет сервер камеры. Добавил документацию к вопросу сейчас. - person PRCube; 11.03.2016
comment
О, если вы используете Android, лучший вариант - использовать камеру дроида и получать доступ к камере телефона как к обычной веб-камере. как и VideoCapture capture = new VideoCapture(number);, я столкнулся с той же проблемой при использовании приложения ip webcam. Проверьте ссылку для настройки здесь dev47apps.com/droidcam/connect - person Collins Abitekaniza; 11.03.2016