15 #include "pandabase.h" 18 #include "openCVTexture.h" 19 #include "clockObject.h" 20 #include "config_gobj.h" 21 #include "config_vision.h" 22 #include "bamReader.h" 23 #include "bamCacheRecord.h" 33 OpenCVTexture(
const string &name) :
45 OpenCVTexture(
const OpenCVTexture ©) :
70 if (this_frame != _last_frame_update) {
71 int frame = get_frame();
72 if (_current_frame != frame) {
74 do_update_frame(cdata, frame);
75 _current_frame = frame;
79 int max_z = max(cdata->_z_size, (
int)_pages.size());
80 for (
int z = 0; z < max_z; ++z) {
81 VideoPage &page = _pages[z];
82 if (!page._color.is_from_file() || !page._alpha.is_from_file()) {
83 do_update_frame(cdata, frame, z);
87 _last_frame_update = this_frame;
107 PT(OpenCVTexture) copy =
new OpenCVTexture(get_name());
109 copy->do_assign(cdata_copy_tex,
this, cdata_tex);
120 do_assign(Texture::CData *cdata_tex,
const OpenCVTexture *copy,
121 const Texture::CData *cdata_copy_tex) {
122 VideoTexture::do_assign(cdata_tex, copy, cdata_copy_tex);
123 _pages = copy->_pages;
140 from_camera(
int camera_index,
int z,
int alpha_file_channel,
143 if (!do_reconsider_z_size(cdata, z, options)) {
146 nassertr(z >= 0 && z < cdata->_z_size,
false);
148 cdata->_alpha_file_channel = alpha_file_channel;
150 VideoPage &page = do_modify_page(cdata, z);
151 if (alpha_file_channel == 0) {
154 if (!page._color.from_camera(camera_index)) {
158 if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
165 if (!page._alpha.from_camera(camera_index)) {
169 if (!do_reconsider_video_properties(cdata, page._alpha, 1, z, options)) {
173 do_set_format(cdata, F_alpha);
176 cdata->_loaded_from_image =
true;
177 clear_current_frame();
178 do_update_frame(cdata, 0);
190 OpenCVTexture::VideoPage &OpenCVTexture::
191 do_modify_page(
const Texture::CData *cdata,
int z) {
192 nassertr(z < cdata->_z_size, _pages[0]);
193 while (z >= (
int)_pages.size()) {
194 _pages.push_back(VideoPage());
207 do_reconsider_video_properties(Texture::CData *cdata,
208 const OpenCVTexture::VideoStream &stream,
209 int num_components,
int z,
211 double frame_rate = 0.0f;
214 if (stream.is_from_file()) {
215 frame_rate = cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FPS);
216 num_frames = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_COUNT);
217 if (vision_cat.is_debug()) {
219 <<
"Loaded " << stream._filename <<
", " << num_frames <<
" frames at " 220 << frame_rate <<
" fps\n";
225 if (vision_cat.is_debug()) {
227 <<
"Loaded camera stream\n";
231 int width = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_WIDTH);
232 int height = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_HEIGHT);
236 do_adjust_this_size(cdata, x_size, y_size, get_name(),
true);
238 if (vision_cat.is_debug()) {
240 <<
"Video stream is " << width <<
" by " << height
241 <<
" pixels; fitting in texture " << x_size <<
" by " 242 << y_size <<
" texels.\n";
245 if (!do_reconsider_image_properties(cdata, x_size, y_size, num_components,
246 T_unsigned_byte, z, options)) {
250 if (cdata->_loaded_from_image &&
251 (get_video_width() != width || get_video_height() != height ||
252 get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
254 <<
"Video properties have changed for texture " << get_name()
255 <<
" level " << z <<
".\n";
259 set_frame_rate(frame_rate);
260 set_num_frames(num_frames);
261 set_video_size(width, height);
278 return new OpenCVTexture;
288 do_update_frame(Texture::CData *cdata,
int frame) {
289 int max_z = max(cdata->_z_size, (
int)_pages.size());
290 for (
int z = 0; z < max_z; ++z) {
291 do_update_frame(cdata, frame, z);
302 do_update_frame(Texture::CData *cdata,
int frame,
int z) {
303 if (vision_cat.is_spam()) {
305 <<
"Updating OpenCVTexture page " << z <<
"\n";
308 VideoPage &page = _pages[z];
309 if (page._color.is_valid() || page._alpha.is_valid()) {
310 do_modify_ram_image(cdata);
311 ++(cdata->_image_modified);
313 int dest_x_pitch = cdata->_num_components * cdata->_component_width;
314 int dest_y_pitch = cdata->_x_size * dest_x_pitch;
316 if (page._color.is_valid()) {
317 nassertv(get_num_components() >= 3 && get_component_width() == 1);
319 const unsigned char *r, *g, *b;
320 int x_pitch, y_pitch;
321 if (page._color.get_frame_data(frame, r, g, b, x_pitch, y_pitch)) {
322 nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
323 nassertv(!cdata->_ram_images.empty())
324 unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
326 if (cdata->_num_components == 3 && x_pitch == 3) {
328 int copy_bytes = get_video_width() * dest_x_pitch;
329 nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch));
331 for (
int y = 0; y < get_video_height(); ++y) {
332 memcpy(dest, r, copy_bytes);
333 dest += dest_y_pitch;
341 for (
int y = 0; y < get_video_height(); ++y) {
344 for (
int x = 0; x < get_video_width(); ++x) {
346 dest[dx + 1] = g[sx];
347 dest[dx + 2] = b[sx];
351 dest += dest_y_pitch;
359 if (page._alpha.is_valid()) {
360 nassertv(get_component_width() == 1);
362 const unsigned char *source[3];
363 int x_pitch, y_pitch;
364 if (page._alpha.get_frame_data(frame, source[0], source[1], source[2],
366 nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
367 nassertv(!cdata->_ram_images.empty())
368 unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
373 const unsigned char *sch = source[0];
374 if (cdata->_alpha_file_channel >= 1 && cdata->_alpha_file_channel <= 3) {
375 sch = source[cdata->_alpha_file_channel - 1];
378 for (
int y = 0; y < get_video_height(); ++y) {
381 int dx = (cdata->_num_components - 1) * cdata->_component_width;
383 for (
int x = 0; x < get_video_width(); ++x) {
388 dest += dest_y_pitch;
403 do_read_one(Texture::CData *cdata,
405 int z,
int n,
int primary_file_num_channels,
int alpha_file_channel,
412 nassertr(n == 0,
false);
413 nassertr(z >= 0 && z < cdata->_z_size,
false);
415 VideoPage &page = do_modify_page(cdata, z);
416 if (!page._color.read(fullpath)) {
418 <<
"OpenCV couldn't read " << fullpath <<
" as video.\n";
421 if (!alpha_fullpath.empty()) {
422 if (!page._alpha.read(alpha_fullpath)) {
424 <<
"OpenCV couldn't read " << alpha_fullpath <<
" as video.\n";
435 if (cdata->_filename.empty()) {
436 cdata->_filename = fullpath;
437 cdata->_alpha_filename = alpha_fullpath;
440 cdata->_fullpath = fullpath;
441 cdata->_alpha_fullpath = alpha_fullpath;
444 cdata->_primary_file_num_channels = 3;
445 cdata->_alpha_file_channel = 0;
447 if (alpha_fullpath.empty()) {
449 if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
456 cdata->_alpha_file_channel = alpha_file_channel;
458 if (!do_reconsider_video_properties(cdata, page._color, 4, z, options)) {
464 if (!do_reconsider_video_properties(cdata, page._alpha, 4, z, options)) {
471 set_loaded_from_image();
472 clear_current_frame();
473 do_update_frame(cdata, 0);
484 do_load_one(Texture::CData *cdata,
485 const PNMImage &pnmimage,
const string &name,
487 if (z <= (
int)_pages.size()) {
488 VideoPage &page = do_modify_page(cdata, z);
493 return Texture::do_load_one(cdata, pnmimage, name, z, n, options);
502 register_with_read_factory() {
522 OpenCVTexture::VideoStream::
535 OpenCVTexture::VideoStream::
536 VideoStream(
const OpenCVTexture::VideoStream ©) :
542 if (copy.is_valid()) {
543 if (copy.is_from_file()) {
544 read(copy._filename);
546 from_camera(copy._camera_index);
556 OpenCVTexture::VideoStream::
584 bool OpenCVTexture::VideoStream::
585 get_frame_data(
int frame,
586 const unsigned char *&r,
587 const unsigned char *&g,
588 const unsigned char *&b,
589 int &x_pitch,
int &y_pitch) {
590 nassertr(is_valid(),
false);
592 if (is_from_file() && _next_frame != frame) {
593 cvSetCaptureProperty(_capture, CV_CAP_PROP_POS_FRAMES, frame);
596 _next_frame = frame + 1;
597 IplImage *image = cvQueryFrame(_capture);
602 r = (
const unsigned char *)image->imageData;
606 y_pitch = image->widthStep;
608 if (image->dataOrder == 1) {
612 g = r + image->height * y_pitch;
613 b = g + image->height * y_pitch;
616 if (image->origin == 0) {
621 r += (image->height - 1) * y_pitch;
622 g += (image->height - 1) * y_pitch;
623 b += (image->height - 1) * y_pitch;
636 bool OpenCVTexture::VideoStream::
641 _capture = cvCaptureFromFile(os_specific.c_str());
642 if (_capture == NULL) {
645 _filename = filename;
655 bool OpenCVTexture::VideoStream::
656 from_camera(
int camera_index) {
659 _capture = cvCaptureFromCAM(camera_index);
660 if (_capture == NULL) {
663 _camera_index = camera_index;
673 void OpenCVTexture::VideoStream::
675 if (_capture != NULL) {
676 cvReleaseCapture(&_capture);
684 #endif // HAVE_OPENCV static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Specifies parameters that may be passed to the loader.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
The base class for a family of animated Textures that take their input from a video source...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
The name of a file, such as a texture file or an Egg file.
int get_frame_count(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of times tick() has been called since the ClockObject was created, or since it was last reset.
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record...
TypeHandle is the identifier used to differentiate C++ class types.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...