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

Итак, я хочу написать программу, чтобы обработанный вывод из OpenCV воспринимался как веб-камера. Я хочу использовать его для создания эффектов для такой программы, как Skype. Я застрял, и поиск в Google не помог. Пожалуйста, помогите мне. Нужен ли мне драйвер для этого? Как насчет хранения в виде AVI и потоковой передачи этого AVI с каким-либо другим приложением?

Я хочу написать программу для маскировки моего лица, поэтому мне не нужно беспокоиться о своей личной жизни, когда я общаюсь по скайпу с людьми, которых я обучаю и не знаю лично!

Кстати, я немного новичок в C++. Тем не менее, это язык, который я предпочитаю. Однако я также понимаю Java и Python.

Вы предлагаете мне попробовать получить другую библиотеку / коллекцию библиотек, например OpenFrameworks?

Я программирую OpenCV на C++. Вот все доступные для меня платформы: Ubuntu: OpenCV из apt-get, с pkg-config, QT Creator Ubuntu: OpenCV из apt-get, с pkg-config и libfreenect, QT Creator Windows 7: OpenCV 2.4.8.0, последние двоичные файлы, x86, Visual Studio 2010 express Windows 7: OpenCV не установлен Windows 8.1 Pro: OpenCV 2.4.8.0, последние двоичные файлы, x86, Visual Studio Express 2013 Express Desktop, Hyper-V, такая же конфигурация, как в Windows 7:1

Я заметил немного растерянности. Я пытаюсь использовать вывод процессов из открытого резюме и отправить его в другую программу, такую ​​как Skype. Главное намерение - научить детей начальной школы программированию и OpenCV. Я бы хотел напрямую транслировать вывод, чтобы мне не пришлось делиться своим рабочим столом.

6 ответов

У меня была такая же проблема: моя бабушка плохо слышит, поэтому я хотел иметь возможность добавлять субтитры в свой канал видео в Skype. Еще я хотел добавить эффекты для смеха. Я не мог заставить работать вебкамоид. Метод захвата экрана (упомянутый выше) казался слишком хакерским, и я не мог заставить Skype обнаруживать фиктивную камеру вывода ffmpegs (хотя guvcview обнаруживает). Потом я наткнулся на это:

https://github.com/jremmons/pyfakewebcam

Это не C++, а Python. Тем не менее, он достаточно быстр на моем обычном ноутбуке. Он может создавать несколько фиктивных веб-камер (мне нужны только две). Он также работает с Python3. Шаги, упомянутые в readme, легко воспроизвести в Ubuntu 18.04. Примерный код был запущен в течение 2-3 минут. На момент написания данной статьи в приведенных здесь примерах не использовался ввод с реальной веб-камеры. Поэтому я добавляю свой код, который обрабатывает входные данные реальной веб-камеры и выводит их на две фиктивные камеры:

import cv2
import time
import pyfakewebcam
import numpy as np

IMG_W = 1280
IMG_H = 720

cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, IMG_W)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, IMG_H)

fake1 = pyfakewebcam.FakeWebcam('/dev/video1', IMG_W, IMG_H)
fake2 = pyfakewebcam.FakeWebcam('/dev/video2', IMG_W, IMG_H)

while True:
    ret, frame = cam.read()

    flipped = cv2.flip(frame, 1)

    # Mirror effect 
    frame[0 : IMG_H, IMG_W//2 : IMG_W] = flipped[0 : IMG_H, IMG_W//2 : IMG_W]

    fake1.schedule_frame(frame)
    fake2.schedule_frame(flipped)

    time.sleep(1/15.0)

Кроссплатформенной альтернативой pyfakewebcam является pyvirtualcam (отказ от ответственности: я ее разработчик). В репозитории есть пример применения фильтра к веб-камере, захваченной OpenCV. Для справки, вот как будет выглядеть код:

      import cv2
import pyvirtualcam
from pyvirtualcam import PixelFormat

vc = cv2.VideoCapture(0)

if not vc.isOpened():
    raise RuntimeError('Could not open video source')

pref_width = 1280
pref_height = 720
pref_fps = 30
vc.set(cv2.CAP_PROP_FRAME_WIDTH, pref_width)
vc.set(cv2.CAP_PROP_FRAME_HEIGHT, pref_height)
vc.set(cv2.CAP_PROP_FPS, pref_fps)

# Query final capture device values
# (may be different from preferred settings)
width = int(vc.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(vc.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = vc.get(cv2.CAP_PROP_FPS)

with pyvirtualcam.Camera(width, height, fps, fmt=PixelFormat.BGR) as cam:
    print('Virtual camera device: ' + cam.device)
    while True:
        ret, frame = vc.read()

        # .. apply your filter ..

        cam.send(frame)
        cam.sleep_until_next_frame()

Итак, я нашел хак для этого; не обязательно лучший метод, но он ОПРЕДЕЛЕННО работает..

Скачайте программу, похожую на SplitCam; это может эмулировать канал веб-камеры из видеофайла, канала IP и / или определенного раздела экрана рабочего стола.

Таким образом, по сути, вы можете написать программу для обработки видео с веб-камеры и отображения ее с помощью окна высокого разрешения OpenCV, а также использовать SplitCam, чтобы использовать это окно в качестве входных данных для любого другого приложения, такого как Skype. Я попробовал это прямо сейчас, это работает отлично.

НТН

Проверьте gstreamer. OpenCV позволяет создавать VideoCapture Объект, который определен как конвейер gstreamer, источником может быть веб-камера или видеофайл. Gstreamer позволяет пользователям создавать фильтры, которые используют opencv или другие библиотеки для изменения видео в цикле, некоторые примеры доступны.

У меня нет опыта жениться на скайпе, но, похоже, это возможно. Просто нужно создать правильный конвейер, что-то вроде:gst-launch videotestsrc ! ffmpegcolorspace ! "video/x-raw-yuv,format=(fourcc)YUY2" ! v4l2sink device=/dev/video1,

Не тривиально, но вы можете изменить "источник виртуальной камеры" с открытым исходным кодом, такой как https://github.com/rdp/screen-capture-recorder-to-video-windows-free чтобы получать входные данные из OpenCV вместо рабочего стола. GL!

Один из способов сделать это - отправить объект Mat непосредственно в сокет, а на полученной стороне преобразовать байтовый массив в Mat, но проблема в том, что вам нужно установить OpenCV на оба компьютера. Другим способом вы можете использовать стример Mjpeg для потоковой передачи видео на ibternet и обработки видео на принимающей стороне, здесь вам нужно установить OpenCV только на принимающей стороне.

Использование сокета

Получите Mat.data и отправьте напрямую в сокет, формат данных будет такой, как BGR BGR BGR.... На принимающей стороне вы должны знать размер изображения, которое вы собираетесь получить. После получения просто назначьте полученный буфер (BGR BGR... массив) мату размера, который вы уже знаете.

Клиент:-

Mat frame;
frame = (frame.reshape(0,1)); // to make it continuous

int  imgSize = frame.total()*frame.elemSize();

// Send data here
bytes = send(clientSock, frame.data, imgSize, 0))

Сервер:-

Mat  img = Mat::zeros( height,width, CV_8UC3);
   int  imgSize = img.total()*img.elemSize();
   uchar sockData[imgSize];

 //Receive data here

   for (int i = 0; i < imgSize; i += bytes) {
   if ((bytes = recv(connectSock, sockData +i, imgSize  - i, 0)) == -1) {
     quit("recv failed", 1);
    }
   }

 // Assign pixel value to img

 int ptr=0;
 for (int i = 0;  i < img.rows; i++) {
  for (int j = 0; j < img.cols; j++) {                                     
   img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[ptr+ 0],sockData[ptr+1],sockData[ptr+2]);
   ptr=ptr+3;
   }
  }

Для программирования сокетов вы можете обратиться по этой ссылке

Использование Mjpeg Streamer

Здесь вам необходимо установить программное обеспечение Mjpeg streamer на ПК, к которому подключена веб-камера, и на все принимающие ПК вам необходимо установить OpenCV и обработать его оттуда. Вы можете напрямую открыть веб-поток, используя класс OpenCV VideoCapture, например

Cap.open("http://192.168.1.30:8080/?dummy=param.mjpg");
Другие вопросы по тегам