Panda3D
|
00001 // Filename: webcamVideoCursorOpenCV.cxx 00002 // Created by: drose (20Oct10) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "webcamVideoOpenCV.h" 00016 00017 #ifdef HAVE_OPENCV 00018 00019 #include "pStatTimer.h" 00020 00021 TypeHandle WebcamVideoCursorOpenCV::_type_handle; 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: WebcamVideoCursorOpenCV::Constructor 00025 // Access: Published 00026 // Description: 00027 //////////////////////////////////////////////////////////////////// 00028 WebcamVideoCursorOpenCV:: 00029 WebcamVideoCursorOpenCV(WebcamVideoOpenCV *src) : MovieVideoCursor(src) { 00030 _size_x = src->_size_x; 00031 _size_y = src->_size_y; 00032 _num_components = 3; 00033 _length = 1.0E10; 00034 _can_seek = false; 00035 _can_seek_fast = false; 00036 _aborted = false; 00037 _last_start = -1.0; 00038 _next_start = 0.0; 00039 _streaming = true; 00040 _ready = false; 00041 00042 _capture = cvCaptureFromCAM(src->_camera_index); 00043 if (_capture != NULL) { 00044 _size_x = (int)cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH); 00045 _size_y = (int)cvGetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT); 00046 _ready = true; 00047 } 00048 } 00049 00050 //////////////////////////////////////////////////////////////////// 00051 // Function: WebcamVideoCursorOpenCV::Destructor 00052 // Access: Published, Virtual 00053 // Description: 00054 //////////////////////////////////////////////////////////////////// 00055 WebcamVideoCursorOpenCV:: 00056 ~WebcamVideoCursorOpenCV() { 00057 if (_capture != NULL) { 00058 cvReleaseCapture(&_capture); 00059 _capture = NULL; 00060 } 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: WebcamVideoCursorOpenCV::fetch_into_buffer 00065 // Access: Published, Virtual 00066 // Description: 00067 //////////////////////////////////////////////////////////////////// 00068 void WebcamVideoCursorOpenCV:: 00069 fetch_into_buffer(double time, unsigned char *block, bool bgra) { 00070 if (!_ready) { 00071 return; 00072 } 00073 00074 unsigned char *dest = block; 00075 int num_components = bgra ? 4 : 3; 00076 ssize_t dest_x_pitch = num_components; // Assume component_width == 1 00077 ssize_t dest_y_pitch = _size_x * dest_x_pitch; 00078 00079 const unsigned char *r, *g, *b; 00080 ssize_t x_pitch, y_pitch; 00081 if (get_frame_data(r, g, b, x_pitch, y_pitch)) { 00082 if (num_components == 3 && x_pitch == 3) { 00083 // The easy case--copy the whole thing in, row by row. 00084 ssize_t copy_bytes = _size_x * dest_x_pitch; 00085 nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch)); 00086 00087 for (int y = 0; y < _size_y; ++y) { 00088 memcpy(dest, r, copy_bytes); 00089 dest += dest_y_pitch; 00090 r += y_pitch; 00091 } 00092 00093 } else { 00094 // The harder case--interleave in the color channels, pixel by 00095 // pixel. 00096 00097 for (int y = 0; y < _size_y; ++y) { 00098 ssize_t dx = 0; 00099 ssize_t sx = 0; 00100 for (int x = 0; x < _size_x; ++x) { 00101 dest[dx] = r[sx]; 00102 dest[dx + 1] = g[sx]; 00103 dest[dx + 2] = b[sx]; 00104 dx += dest_x_pitch; 00105 sx += x_pitch; 00106 } 00107 dest += dest_y_pitch; 00108 r += y_pitch; 00109 g += y_pitch; 00110 b += y_pitch; 00111 } 00112 } 00113 } 00114 } 00115 00116 //////////////////////////////////////////////////////////////////// 00117 // Function: WebcamVideoCursorOpenCV::get_frame_data 00118 // Access: Private 00119 // Description: Gets the data needed to traverse through the 00120 // decompressed buffer. Returns true on success, false 00121 // on failure. 00122 // 00123 // In the case of a success indication (true return 00124 // value), the three pointers r, g, b are loaded with 00125 // the addresses of the three components of the 00126 // bottom-left pixel of the image. (They will be 00127 // adjacent in memory in the case of an interleaved 00128 // image, and separated in the case of a 00129 // separate-channel image.) The x_pitch value is filled 00130 // with the amount to add to each pointer to advance to 00131 // the pixel to the right; and the y_pitch value is 00132 // filled with the amount to add to each pointer to 00133 // advance to the pixel above. Note that these values 00134 // may be negative (particularly in the case of a 00135 // top-down image). 00136 //////////////////////////////////////////////////////////////////// 00137 bool WebcamVideoCursorOpenCV:: 00138 get_frame_data(const unsigned char *&r, 00139 const unsigned char *&g, 00140 const unsigned char *&b, 00141 ssize_t &x_pitch, ssize_t &y_pitch) { 00142 nassertr(ready(), false); 00143 00144 IplImage *image = cvQueryFrame(_capture); 00145 if (image == NULL) { 00146 return false; 00147 } 00148 00149 r = (const unsigned char *)image->imageData; 00150 g = r + 1; 00151 b = g + 1; 00152 x_pitch = 3; 00153 y_pitch = image->widthStep; 00154 00155 if (image->dataOrder == 1) { 00156 // Separate channel images. That means a block of r, followed by 00157 // a block of g, followed by a block of b. 00158 x_pitch = 1; 00159 g = r + image->height * y_pitch; 00160 b = g + image->height * y_pitch; 00161 } 00162 00163 if (image->origin == 0) { 00164 // The image data starts with the top row and ends with the bottom 00165 // row--the opposite of Texture::_ram_data's storage convention. 00166 // Therefore, we must increment the initial pointers to the last 00167 // row, and count backwards. 00168 r += (image->height - 1) * y_pitch; 00169 g += (image->height - 1) * y_pitch; 00170 b += (image->height - 1) * y_pitch; 00171 y_pitch = -y_pitch; 00172 } 00173 00174 return true; 00175 } 00176 00177 #endif