カメラの画像を処理してv4l2loopbackに放り込む方法。
いい加減、githubを使うべきな気もしている。
//////liboutstream.h/////
#ifdef __cplusplus
extern "C"{
#endif
int writeData(int devfd, unsigned char* data, int length);
int close_write_device(int devfd);
int open_write_device(char* dev, int width, int height, int pixFormat);
#ifdef __cplusplus
}
#endif
#define PIX_FMT_RGB24 1
#define PIX_FMT_UYVY 2
#define PIX_FMT_BGR24 3
////liboutstream.c/////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#define PIX_FMT_RGB24 1
#define PIX_FMT_UYVY 2
#define PIX_FMT_BGR24 3
static void errno_exit(const char *s){
fprintf(stderr, "%s error %d, %s\n",s, errno, strerror(errno));
exit(EXIT_FAILURE);
}
static int xioctl(int fd,int request,void *arg){
int r;
do{ r = ioctl(fd, request, arg); }
while(-1 == r && EINTR == errno);
return r;
}
int writeData(int devfd, __u8 * data, int length) {
__u8 tmp;
int i;
/*These codes may be for YUVU format.
* Now, main code uses RGB format.
* These codes are not required. */
/*
for(i = 0; i < length; i = i + 2){
tmp = *(data + i);
*(data + i) = *(data + i + 1);
*(data + i + 1) = tmp;
}
*/
int retValue = write(devfd, data, length);
return retValue;
}
int close_write_device(int devfd) {
close(devfd);
return 0;
}
int open_write_device(char* dev, int width, int height, int pixFormat){
struct v4l2_capability vid_caps;
struct v4l2_format vid_format;
memset(&vid_format, 0, sizeof(vid_format));
// vid_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
vid_format.fmt.pix.width = width;
vid_format.fmt.pix.height = height;
//printf("format : %d %d %d\n", pixFormat, vid_format.fmt.pix.width, vid_format.fmt.pix.height);
switch (pixFormat) {
case PIX_FMT_RGB24:
vid_format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
vid_format.fmt.pix.bytesperline = (width * 3);
vid_format.fmt.pix.sizeimage = (width * height * 3);
printf("uuu %d\n", V4L2_PIX_FMT_RGB24);
break;
// UYVY has only half the color resolution of RGB, but there is less confusion
// surrounding its byte ordering
case PIX_FMT_UYVY:
vid_format.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
vid_format.fmt.pix.bytesperline = (width * 2);
vid_format.fmt.pix.sizeimage = (width * height * 2);
printf("ppp %d\n", V4L2_PIX_FMT_UYVY);
break;
// Adding BGR24 as format #3 in anticipation of Chrome hopefully adopting it in the future
// (After all, BGR24 is what they actually implemented, they just call it RGB24)
case PIX_FMT_BGR24:
vid_format.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
vid_format.fmt.pix.bytesperline = (width * 3);
vid_format.fmt.pix.sizeimage = (width * height * 3);
break;
default:
// Unknown pixFormat, bail out.
return -1;
}
vid_format.fmt.pix.field = V4L2_FIELD_NONE;
vid_format.fmt.pix.priv = 0;
vid_format.fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
int fdwr = open(dev, O_RDWR, O_NONBLOCK);
int ret_code = xioctl(fdwr, VIDIOC_QUERYCAP, &vid_caps);
//printf("qqq %d\n", vid_format.fmt.pix.pixelformat);
if(ret_code = xioctl(fdwr, VIDIOC_S_FMT, &vid_format) == -1){
errno_exit("VIDIOC_S_FMT");
}
//printf("vvv %d %d %d\n", fdwr, ret_code, vid_format.fmt.pix.pixelformat);
fflush(stdout);
return fdwr;
}
/////main.cpp/////
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp> // highguiのヘッダーをインクルード
#include <iostream>
#include <webcam.h>
#include "liboutstream.h"
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
#define WRITE_DEV_NAME "/dev/video7"
int main(int, char**){
CResult ret;
CHandle handle;
CControlValue value;
bool loop = true;
int write_fd;
Mat frame, edge, result;
VideoCapture cap(0); // デフォルトカメラをオープン
if(!cap.isOpened()){ // 成功したかどうかをチェック
return -1;
}
//cap.set(CAP_PROP_FRAME_WIDTH, 1920); //too large
//cap.set(CAP_PROP_FRAME_HEIGHT, 1080); //too large
//cap.set(CAP_PROP_FPS, 5); //for 1920 x 1080
//Mat edges;
namedWindow("frame",1);
//initialize webcam
ret = c_init();
if(ret){
cout << "Error : c_init() : " << ret << "\n";
loop = false;
return 1;
}
handle = c_open_device("video0");
if(!handle){
cout << "Error : c_open_device() : " << ret << "\n";
c_cleanup();
return 1;
}
ret = c_get_control(handle, CC_AUTO_FOCUS, &value);
value.value = 0;
if(ret){
cout << "Error : c_get_control() (init) : " << ret << "\n";
loop = false;
return 1;
}
ret = c_set_control(handle, CC_AUTO_FOCUS, &value);
if(ret){
cout << "Error : c_set_control() (init): " << ret << "\n";
loop = false;
return 1;
}
cap >> frame;
cout << frame.cols << " " << frame.rows << "!!!\n\n";
write_fd = open_write_device(WRITE_DEV_NAME, frame.cols, frame.rows, PIX_FMT_RGB24); //PIX_FMT_UYVY);
while(loop){
cap >> frame; // カメラから新しいフレームを取得
cvtColor(frame, edge, COLOR_RGB2GRAY);
GaussianBlur(edge, edge, Size(7,7), 1.5, 1.5);
Canny(edge, edge, 0, 15, 3);
cvtColor(edge, result, COLOR_GRAY2RGB);
imshow("frame", result);
writeData(write_fd, result.data, result.cols * result.rows * 3);
switch(waitKey(30)){
//Logicool C615 focus has 17 values, 0, 17, 34, 51, , , 238, 255
case 'p':
c_get_control(handle, CC_FOCUS_ABSOLUTE, &value);
value.value += 17;
c_set_control(handle, CC_FOCUS_ABSOLUTE, &value);
ret = c_get_control(handle, CC_FOCUS_ABSOLUTE, &value);
cout << value.value << "\n";
break;
case 'm':
c_get_control(handle, CC_FOCUS_ABSOLUTE, &value);
value.value -= 17;
c_set_control(handle, CC_FOCUS_ABSOLUTE, &value);
ret = c_get_control(handle, CC_FOCUS_ABSOLUTE, &value);
cout << value.value << "\n";
break;
case 'e':
loop = false;
break;
default:
break;
}
}
close_write_device(write_fd);
c_close_device(handle);
c_cleanup();
// VideoCapture デストラクタにより,カメラは自動的に終了処理されます
return 0;
}
/////Makefile/////
CC = g++
CFLAGS =
CFLAGS_TMP = `pkg-config opencv --cflags` `pkg-config opencv --libs`
LDFLAGS = -L./ -L/usr/local/lib
INCLUDE = -I./ -I/usr/local/include/opencv4 -I/usr/include -I/usr/local/include
LIBS = -lopencv_core -lopencv_videoio -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc -lm -lwebcam -loutstream
main: main.o
$(CC) $(CFLAGS) -o $@ $< $(INCLUDE) $(LDFLAGS) $(LIBS)
rm *.o
rm *.a
# rm *~
.cpp.o:
gcc -c liboutstream.c -o liboutstream.o
ar r liboutstream.a liboutstream.o
g++ -o $@ -c $< $(INCLUDE)