天天看點

mjpg_streamer源碼的分析及針對圖像處理算法的修改

mjpg_streamer源碼的分析及針對圖像處理算法的修改

  最近在研究mjpg_streamer,發現這是個好東西,關于mjpg_streamer就不做具體介紹了,總之它是在Linux上運作的視訊伺服器,可以将攝像頭采集到的視訊資料通過網絡傳輸到用戶端,實作視訊監控,mjpg_streamer是開源項目。

  首先簡要的分析一下mjpg_streamer的源碼及其工作過程。我主要參考了這裡:Mjpeg-streamer源碼分析,另外可以參考這裡:http://blog.csdn.net/wavemcu/article/details/7795561。在“Mjpeg-streamer源碼分析”一文中已經對mjpg_streamer的源代碼做了比較詳細的分析,這裡隻做簡要概括。mjpg_streamer主要由三部分構成,主函數mjpg_streamer.c和輸入、輸出元件,其中輸入、輸出元件通常是input_uvc.so和output_http.so,他們是以動态連結庫的形式在主函數中調用的。

  主函數的主要功能有:1.解析指令行的各個輸入參數。2.判斷程式是否需要成為守護程序,如果需要,則執行相應的操作。3.初始化global全局變量。4.打開并配置輸入、輸出插件。5.運作輸入、輸出插件。

  輸入插件将采集到的視訊送到全局緩存中,輸出插件則從全局緩存中讀取資料并發送。輸出插件的實作是一個http伺服器,這裡就不介紹了。輸入插件的視訊采集功能主要是通過Linux的V4L2接口實作的,主要是4個函數input_init()、 input_stop()、 input_run()和 input_cmd()。其中iniput_run()函數建立了線程cma_thread(),這個線程很重要,該函數的作用是抓取一幀的圖像,并複制到全局緩沖區。具體的代碼說明請參考連結中的分析。

  mjpg_streamer的功能的确強大,但是由于我的主要研究方向是圖像處理,是以也想到了一些問題。現在的網絡視訊監控系統除了傳統的視訊傳輸功能外,大多還有視訊分析的能力,即在圖像捕獲和圖像傳輸之間加上了圖像處理的能力,例如能夠檢測移動目标,這樣視訊監控伺服器的功能就大大增強了。mjpg_streamer是一個很好的視訊伺服器架構,那麼它否能夠通過修改而擁有視訊圖像處理能力呢?為此我也查閱了很多資料,同時發現了另一個開源項目motion。關于motion的詳細資訊可以參考這裡:http://www.lavrsen.dk/foswiki/bin/view/Motion。motion的移植可以參考這裡:http://blog.csdn.net/kangear/article/details/8763790。

  motion實際上功能類似于mjpg_streamer,但是正如它的名字,除了能夠捕獲和傳輸視訊外,它還擁有運動檢測的功能,能夠将檢測到的運動物體辨別出來,并且檢測到移動物體後可以執行使用者腳本,實作報警等功能,非常強大。但是motion也有他的局限性,它隻能單純的檢測移動物體,如果想要做更複雜的或者有針對性的算法就沒有辦法了,比如車輛檢測、火災監測、人臉識别等等。鑒于mjpg_streamer的源代碼比較易讀,思路清晰,我準備修改它的源碼來支援圖像處理功能。通過前面mjpg_streamer的源碼分析可知要實作圖像處理功能,應該從輸入元件input_uvc.so下手。

  在input_uvc.c檔案中有一個線程是cam_thread()前面已經提到過了,其作用是抓取一幀的圖像,并複制到全局緩沖區。如果在抓取一幀圖像後先進行處理,在複制到全局緩沖區就能實作目标。下面是cam_thread()的代碼:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
1 void *cam_thread( void *arg ) {
 2   /* set cleanup handler to cleanup allocated ressources */
 3   pthread_cleanup_push(cam_cleanup, NULL);
 4   while( !pglobal->stop ) {
 5     /* grab a frame */
 6     if( uvcGrab(videoIn) < 0 ) {
 7       IPRINT("Error grabbing frames\n");
 8       exit(EXIT_FAILURE);
 9     }
10     DBG("received frame of size: %d\n", videoIn->buf.bytesused);
11     /*
12      * Workaround for broken, corrupted frames:
13      * Under low light conditions corrupted frames may get captured.
14      * The good thing is such frames are quite small compared to the regular pictures.
15      * For example a VGA (640x480) webcam picture is normally >= 8kByte large,
16      * corrupted frames are smaller.
17      */
18     if ( videoIn->buf.bytesused < minimum_size ) {
19       DBG("dropping too small frame, assuming it as broken\n");
20       continue;
21     }
22     /* copy JPG picture to global buffer */
23     pthread_mutex_lock( &pglobal->db );
24     /*
25      * If capturing in YUV mode convert to JPEG now.
26      * This compression requires many CPU cycles, so try to avoid YUV format.
27      * Getting JPEGs straight from the webcam, is one of the major advantages of
28      * Linux-UVC compatible devices.
29      */
30     if (videoIn->formatIn == V4L2_PIX_FMT_YUYV) {
31       DBG("compressing frame\n");
32       pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality);
33     }
34     else {
35       DBG("copying frame\n");
36       pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);
37     }
38 #if 0
39     /* motion detection can be done just by comparing the picture size, but it is not very accurate!! */
40     if ( (prev_size - global->size)*(prev_size - global->size) > 4*1024*1024 ) {
41         DBG("motion detected (delta: %d kB)\n", (prev_size - global->size) / 1024);
42     }
43     prev_size = global->size;
44 #endif
45     /* signal fresh_frame */
46     pthread_cond_broadcast(&pglobal->db_update);
47     pthread_mutex_unlock( &pglobal->db );
48     DBG("waiting for next frame\n");
49     /* only use usleep if the fps is below 5, otherwise the overhead is too long */
50     if ( videoIn->fps < 5 ) {
51       usleep(1000*1000/videoIn->fps);
52     }
53   }
54   DBG("leaving input thread, calling cleanup function now\n");
55   pthread_cleanup_pop(1);
56   return NULL;
57 }      
mjpg_streamer源碼的分析及針對圖像處理算法的修改

22行——37行的代碼實作了将圖像資料拷貝到全局緩沖區,if語句針對的是輸出YUYV格式的攝像頭,在拷貝資料之前還要進行資料轉換,将YUYV格式利用libjpeg庫轉換成jpg格式再進行拷貝。關于libjpeg庫的移植方法可以參考這裡:http://blog.chinaunix.net/uid-11765716-id-172491.html。else語句針對輸出格式為jpg的攝像頭,它直接将資料拷貝到全局緩沖區,無需轉換。

  由于我使用的攝像頭是中星微zc301,直接輸出jpg格式,是以這裡隻讨論這種情況的修改方法。從上面代碼中我們可以看出,我們隻需要在21行與22行之間增加處理算法就能實作相應的功能。要進行圖像處理,首先要将采集到的jpg圖像轉換為RGB或YUV,然後再由RGB或YUV轉換為灰階,對灰階圖像進行處理,完成之後再轉換為jpg格式,最後拷貝到全局緩沖。而jpg與RGB或YUV格式的轉換還要靠libjpeg庫來實作。但是libjpeg庫有個缺陷:它隻能對檔案進行轉換,而我們的資料在記憶體中,是以需要對libjpeg庫進行一定的修改。幸運的是我在motion項目中發現了jpg與YUV轉換的代碼,經過簡單修改後可以直接使用。相應的檔案是jpegutils.h和jpegutils.c,将他們放入mjpg-streamer/plugins/input_uvc/中即可。這是經過修改的檔案:jpegutils。要用到的兩個函數如下,分别是将jpg資料解碼為YUV和将YUV編碼成jpg。

mjpg_streamer源碼的分析及針對圖像處理算法的修改
1 int decode_jpeg_raw(unsigned char *jpeg_data, int len,
2                     int itype, int ctype, unsigned int width, 
3                     unsigned int height, unsigned char *raw0, 
4                     unsigned char *raw1, unsigned char *raw2);
5 
6 int encode_jpeg_raw(unsigned char *jpeg_data, int len, int quality,
7                     int itype, int ctype, unsigned int width, 
8                     unsigned int height, unsigned char *raw0, 
9                     unsigned char *raw1, unsigned char *raw2);      
mjpg_streamer源碼的分析及針對圖像處理算法的修改

  将jpg資料解碼為YUV資料後,由于Y代表亮度,即灰階。我們隻需要對Y分量做處理即可,最後再編碼為jpg資料。下面附上修改後的input_uvc.c檔案:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <string.h>
  5 #include <linux/videodev.h>
  6 #include <sys/ioctl.h>
  7 #include <errno.h>
  8 #include <signal.h>
  9 #include <sys/socket.h>
 10 #include <arpa/inet.h>
 11 #include <sys/types.h>
 12 #include <sys/stat.h>
 13 #include <getopt.h>
 14 #include <pthread.h>
 15 #include <syslog.h>
 16 #include <math.h>
 17 
 18 #include "../../utils.h"
 19 #include "../../mjpg_streamer.h"
 20 #include "v4l2uvc.h"
 21 #include "huffman.h"
 22 #include "jpeg_utils.h"
 23 #include "jpegutils.h"
 24 #include "dynctrl.h"
 25 
 26 #define INPUT_PLUGIN_NAME "UVC webcam grabber"
 27 #define MAX_ARGUMENTS 32
 28 
 29 /*
 30  * UVC resolutions mentioned at: (at least for some webcams)
 31  * http://www.quickcamteam.net/hcl/frame-format-matrix/
 32  */
 33 static const struct {
 34   const char *string;
 35   const int width, height;
 36 } resolutions[] = {
 37   { "QSIF", 160,  120  },
 38   { "QCIF", 176,  144  },
 39   { "CGA",  320,  200  },
 40   { "QVGA", 320,  240  },
 41   { "CIF",  352,  288  },
 42   { "VGA",  640,  480  },
 43   { "SVGA", 800,  600  },
 44   { "XGA",  1024, 768  },
 45   { "SXGA", 1280, 1024 }
 46 };
 47 
 48 /* private functions and variables to this plugin */
 49 pthread_t cam;
 50 pthread_mutex_t controls_mutex;
 51 struct vdIn *videoIn;
 52 static globals *pglobal;
 53 static int gquality = 80;
 54 static unsigned int minimum_size = 0;
 55 static int dynctrls = 1;
 56 
 57 //jpeg壓縮、解壓縮
 58 unsigned char *y,*u,*v,*processed_jpeg_data;
 59 
 60 void *cam_thread( void *);
 61 void cam_cleanup(void *);
 62 void help(void);
 63 int input_cmd(in_cmd_type, int);
 64 
 65 int input_init(input_parameter *param) {
 66 
 67 /////此處省略n行/
 68 void *cam_thread( void *arg ) {
 69     /*********************利用libjpeg庫實作jpeg圖像段壓縮、解壓縮*********************/
 70     int i,j;
 71     int length=sizeof(unsigned char)*videoIn->width*videoIn->height;
 72     y=(unsigned char *)malloc(length);
 73     u=(unsigned char *)malloc(length/4);
 74     v=(unsigned char *)malloc(length/4);
 75     processed_jpeg_data=(unsigned char *)malloc(length);
 76     memset(y,0,length);
 77     memset(u,0,length/4);
 78     memset(v,0,length/4);
 79     memset(processed_jpeg_data,0,length);
 80   /* set cleanup handler to cleanup allocated ressources */
 81   pthread_cleanup_push(cam_cleanup, NULL);
 82   while( !pglobal->stop ) {
 83     /* grab a frame */
 84     if( uvcGrab(videoIn) < 0 ) {
 85       IPRINT("Error grabbing frames\n");
 86       exit(EXIT_FAILURE);
 87     } 
 88     DBG("received frame of size: %d\n", videoIn->buf.bytesused);
 89     /*
 90      * Workaround for broken, corrupted frames:
 91      * Under low light conditions corrupted frames may get captured.
 92      * The good thing is such frames are quite small compared to the regular pictures.
 93      * For example a VGA (640x480) webcam picture is normally >= 8kByte large,
 94      * corrupted frames are smaller.
 95      */
 96     if ( videoIn->buf.bytesused < minimum_size ) {
 97       DBG("dropping too small frame, assuming it as broken\n");
 98       continue;
 99     }
100     //将輸入的jpeg圖像解壓成YUV分量
101     decode_jpeg_raw(videoIn->tmpbuffer,videoIn->buf.bytesused,0,420,videoIn->width,videoIn->height,y,u,v);
102     //這裡可以對Y分量進行更改加入圖像處理算法
103     /*二值化*/
104     /*for(i=0;i<videoIn->height;i++)
105         for(j=0;j<videoIn->width;j++) {
106             if (*(y+i*videoIn->width+j)>128)
107                 *(y+i*videoIn->width+j)=250;
108             else 
109                 *(y+i*videoIn->width+j)=0;}*/
110     /*負片*/
111     for(i=0;i<videoIn->height;i++)
112         for(j=0;j<videoIn->width;j++)
113             *(y+i*videoIn->width+j)=255-*(y+i*videoIn->width+j);
114     /*sobel濾波*/
115     /*
116     int m,n,edge;//m,n為x,y方向上的梯度
117     for(i=1;i<videoIn->height-1;i++)
118         for(j=1;j<videoIn->width;j++)
119             {
120                 m=*(y+(i-1)*videoIn->width+(j+1))+*(y+i*videoIn->width+(j+1))*2+*(y+(i+1)*videoIn->width+(j+1))\
121                  -*(y+(i-1)*videoIn->width+(j-1))-*(y+i*videoIn->width+(j-1))*2-*(y+(i+1)*videoIn->width+(j-1));
122                 n=*(y+(i-1)*videoIn->width+(j-1))+*(y+(i-1)*videoIn->width+j)*2+*(y+(i-1)*videoIn->width+(j+1))\
123                  -*(y+(i+1)*videoIn->width+(j-1))-*(y+(i+1)*videoIn->width+j)*2-*(y+(i+1)*videoIn->width+(j+1));
124                 edge=(int)sqrt((float)m*m+(float)n*n)+0.5;
125                 //if(edge>255)
126                     //edge=255;
127                 *(y+i*videoIn->width+j)=edge> 450?250 : 20;
128 
129             }*/
130     //将UV分量設定為128,壓縮後為灰階圖像
131     memset(u,128,length/4);
132     memset(v,128,length/4);
133     //将YUV分量壓縮成jpeg
134     encode_jpeg_raw(processed_jpeg_data,length,80,0,420,videoIn->width,videoIn->height,y,u,v);
135     
136     //free()在後面不要忘了!
137     
138     /* copy JPG picture to global buffer */
139     pthread_mutex_lock( &pglobal->db );
140 
141     /*
142      * If capturing in YUV mode convert to JPEG now.
143      * This compression requires many CPU cycles, so try to avoid YUV format.
144      * Getting JPEGs straight from the webcam, is one of the major advantages of
145      * Linux-UVC compatible devices.
146      */
147     if (videoIn->formatIn == V4L2_PIX_FMT_YUYV) {
148       DBG("compressing frame\n");
149       pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality);
150     }
151     else {
152       DBG("copying frame\n");
153       //pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);
154       //将新壓縮的jpeg圖像複制到全局緩沖區
155       pglobal->size = memcpy_picture(pglobal->buf,processed_jpeg_data, videoIn->width*videoIn->height);
156     }
157 #if 0
158     /* motion detection can be done just by comparing the picture size, but it is not very accurate!! */
159     if ( (prev_size - global->size)*(prev_size - global->size) > 4*1024*1024 ) {
160         DBG("motion detected (delta: %d kB)\n", (prev_size - global->size) / 1024);
161     }
162     prev_size = global->size;
163 #endif
164     /* signal fresh_frame */
165     pthread_cond_broadcast(&pglobal->db_update);
166     pthread_mutex_unlock( &pglobal->db );
167     DBG("waiting for next frame\n");
168     /* only use usleep if the fps is below 5, otherwise the overhead is too long */
169     if ( videoIn->fps < 5 ) {
170       usleep(1000*1000/videoIn->fps);
171     }
172   }
173   DBG("leaving input thread, calling cleanup function now\n");
174   pthread_cleanup_pop(1);
175   return NULL;
176 }
177 
178 void cam_cleanup(void *arg) {
179   static unsigned char first_run=1;
180   if ( !first_run ) {
181     DBG("already cleaned up ressources\n");
182     return;
183   }
184   first_run = 0;
185   IPRINT("cleaning up ressources allocated by input thread\n");
186   /* restore behaviour of the LED to auto */
187   input_cmd(IN_CMD_LED_AUTO, 0);
188   close_v4l2(videoIn);
189   if (videoIn->tmpbuffer != NULL) free(videoIn->tmpbuffer);
190   if (videoIn != NULL) free(videoIn);
191   if (pglobal->buf != NULL) free(pglobal->buf);
192   //釋放jpeg壓縮、解壓縮緩存
193   if (y != NULL) free(y);
194   if (u != NULL) free(u);
195   if (v != NULL) free(v);
196   if (processed_jpeg_data != NULL) free(processed_jpeg_data);
197 }      
mjpg_streamer源碼的分析及針對圖像處理算法的修改

程式中實作了二值化、負片和sobel濾波效果。

  除了修改源碼外,還需要修改input_uvc檔案夾内的Makefile,修改如下:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
###############################################################
#
# Purpose: Makefile for "M-JPEG Streamer"
# Author.: Tom Stoeveken (TST)
# Version: 0.3
# License: GPL
#
###############################################################

CC = arm-linux-gcc

OTHER_HEADERS = ../../mjpg_streamer.h ../../utils.h ../output.h ../input.h

CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC
#CFLAGS += -DDEBUG
LFLAGS += -ljpeg -lm #for math.h

all: input_uvc.so

clean:
    rm -f *.a *.o core *~ *.so *.lo

input_uvc.so: $(OTHER_HEADERS) input_uvc.c v4l2uvc.lo dynctrl.lo jpeg_utils.lo jpegutils.lo
    $(CC) $(CFLAGS) $(LFLAGS) -o $@ input_uvc.c v4l2uvc.lo dynctrl.lo jpeg_utils.lo jpegutils.lo

v4l2uvc.lo: huffman.h uvc_compat.h uvcvideo.h v4l2uvc.c v4l2uvc.h
    $(CC) -c $(CFLAGS) -o $@ v4l2uvc.c

jpeg_utils.lo: jpeg_utils.c jpeg_utils.h
    $(CC) -c $(CFLAGS) -o $@ jpeg_utils.c

dynctrl.lo: dynctrl.c dynctrl.h uvcvideo.h
    $(CC) -c $(CFLAGS) -o $@ dynctrl.c

jpegutils.lo: jpegutils.c jpegutils.h
    $(CC) -c $(CFLAGS) -o $@ jpegutils.c      
mjpg_streamer源碼的分析及針對圖像處理算法的修改

  編譯完成後通過TQ2440進行測試,在終端中啟動mjpg_streamer,用戶端輸出結果如下:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
mjpg_streamer源碼的分析及針對圖像處理算法的修改

  至此修改終于成功了。用戶端軟體看這裡:http://www.armbbs.net/forum.php?mod=viewthread&tid=17042。除了使用用戶端軟體,還可以直接使用浏覽器檢視。

  但是修改還沒有結束,以上使用了自己編寫代碼的方法實作了圖像處理功能,Opencv是圖像處理利器,如果能進一步将Opencv應用到這裡,能夠大大簡化我們的代碼量,同時能夠實作更複雜的算法。Opencv在x86 Linux和arm_linux上的移植我已經成功實作了,看我的另一篇博文:Opencv2.3.1在ubuntu10.04和TQ2440 arm-linux上的移植與測試。

  這裡我們進行背景差分算法的實作。主要參考了Opencv官網中的讀視訊檔案和運動檢測範例,此外涉及到IplImage類型與unsigned char*類型資料轉換的問題,參考了BMP與IplImage互相轉換範例。

      使用Opencv需要加入頭檔案:

#include "cv.h"
#include "highgui.h"      

主要算法如下:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
1 //将輸入的jpeg圖像解壓成YUV分量
 2     decode_jpeg_raw(videoIn->tmpbuffer,videoIn->buf.bytesused,0,420,videoIn->width,videoIn->height,y,u,v);
 3     //這裡可以對Y分量進行更改加入圖像處理算法
 4     framenumber++;
 5     pFrame->imageData=(char *)y;
 6     //Canny算子
 7     //cvCanny(pImg, pCannyImg, 50, 150, 3);
 8     if(framenumber == 1)
 9     {
10       pBkImg = cvCreateImage(cvSize(videoIn->width,videoIn->height),  IPL_DEPTH_8U,1);
11       pFrImg = cvCreateImage(cvSize(videoIn->width,videoIn->height),  IPL_DEPTH_8U,1);
12  
13       pBkMat = cvCreateMat(videoIn->height, videoIn->width, CV_32FC1);
14       pFrMat = cvCreateMat(videoIn->height, videoIn->width, CV_32FC1);
15       pFrameMat = cvCreateMat(videoIn->height, videoIn->width, CV_32FC1);
16  
17       //轉化成單通道圖像再處理
18       pBkImg=pFrame;//目前幀為背景
19       pFrImg=pFrame;//目前幀轉為灰階并作為前景
20  
21       cvConvert(pFrImg, pFrameMat);//圖像轉為矩陣,以便計算
22       cvConvert(pFrImg, pFrMat);
23       cvConvert(pFrImg, pBkMat);
24     }
25     else //從第2幀開始
26     {
27       pFrImg=pFrame;//将目前幀作為前景并轉灰階
28       cvConvert(pFrImg, pFrameMat);
29       //高斯濾波先,以平滑圖像
30       cvSmooth(pFrameMat, pFrameMat, CV_GAUSSIAN, 3, 0, 0,0);
31  
32       //目前幀跟背景圖相減
33       cvAbsDiff(pFrameMat, pBkMat, pFrMat);//計算目前幀與背景的差的絕對值,作為前景
34  
35       //二值化前景圖
36       cvThreshold(pFrMat, pFrImg, 60, 255.0, CV_THRESH_BINARY);
37  
38       //進行形态學濾波,去掉噪音  
39       cvErode(pFrImg, pFrImg, 0, 1);
40       cvDilate(pFrImg, pFrImg, 0, 1);
41  
42       //更新背景,背景自動更新,權值0.003
43       cvRunningAvg(pFrameMat, pBkMat, 0.03, 0);
44       
45       //将UV分量設定為128,壓縮後為灰階圖像
46       memset(u,128,length/4);
47       memset(v,128,length/4);
48       //将YUV分量壓縮成jpeg
49       encode_jpeg_raw(processed_jpeg_data,length,80,0,420,videoIn->width,videoIn->height,(unsigned char *)pFrImg->imageData,u,v);
50     }      
mjpg_streamer源碼的分析及針對圖像處理算法的修改

附上使用Opencv的Makefile:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
###############################################################
#
# Purpose: Makefile for "M-JPEG Streamer"
# Author.: Tom Stoeveken (TST)
# Version: 0.3
# License: GPL
#
###############################################################

CC = arm-linux-gcc

OTHER_HEADERS = ../../mjpg_streamer.h ../../utils.h ../output.h ../input.h

#################OpenCV Package Information for pkg-config##############
prefix=/opt/EmbedSky/opencv_arm
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir_old=${prefix}/include/opencv
includedir_new=${prefix}/include
#
#Name: OpenCV
#Description: Open Source Computer Vision Library
#Version: 2.3.1
#Libs: -L${libdir} -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -#lopencv_contrib -lopencv_legacy -lopencv_flann -lpthread -lrt
#Cflags: -I${includedir_old} -I${includedir_new}
CV_LFLAGS += -ljpeg -L${libdir} -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann -lpthread -lrt 
CV_CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC -I${includedir_old} -I${includedir_new}
##########end#############################################
CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC
#CFLAGS += -DDEBUG
LFLAGS += -ljpeg -lm #for math.h

all: input_uvc.so

clean:
    rm -f *.a *.o core *~ *.so *.lo

input_uvc.so: $(OTHER_HEADERS) input_uvc.c v4l2uvc.lo dynctrl.lo jpeg_utils.lo jpegutils.lo
    $(CC) $(CV_CFLAGS) $(CV_LFLAGS) -o $@ input_uvc.c v4l2uvc.lo dynctrl.lo jpeg_utils.lo jpegutils.lo

v4l2uvc.lo: huffman.h uvc_compat.h uvcvideo.h v4l2uvc.c v4l2uvc.h
    $(CC) -c $(CFLAGS) -o $@ v4l2uvc.c

jpeg_utils.lo: jpeg_utils.c jpeg_utils.h
    $(CC) -c $(CFLAGS) -o $@ jpeg_utils.c

dynctrl.lo: dynctrl.c dynctrl.h uvcvideo.h
    $(CC) -c $(CFLAGS) -o $@ dynctrl.c

jpegutils.lo: jpegutils.c jpegutils.h
    $(CC) -c $(CFLAGS) -o $@ jpegutils.c      
mjpg_streamer源碼的分析及針對圖像處理算法的修改

編譯成功後放到開發闆驗證,結果如下:

mjpg_streamer源碼的分析及針對圖像處理算法的修改
mjpg_streamer源碼的分析及針對圖像處理算法的修改
mjpg_streamer源碼的分析及針對圖像處理算法的修改

前兩張圖是建立背景,第三張是背景差分結果,從圖中可以看出背景差分效果很好。

  至此,我們已經能夠成功将Opencv應用于mjpg_streamer項目中,為實作更複雜的算法打下了基礎。值得一提的是,此次我使用的驗證平台是TQ2440,雖然修改後的mjpg_streamer能夠成功運作,但是速度實在不敢恭維。如果能夠使用更高端的晶片驗證,相信效果會更流暢。

  最後附上修改後的項目源碼:my_mjpg_streamer

  

分類: C/C++, Linux 标簽: mjpg_streamer, 圖像處理, opencv

繼續閱讀