29 #include <opencv2/core/core.hpp> 31 #include <opencv2/highgui/highgui.hpp> 38 #endif // OPENCV_VER_23 46 OpenCVTexture(
const std::string &name) :
64 if (this_frame != _last_frame_update) {
65 int frame = get_frame();
66 if (_current_frame != frame) {
68 do_update_frame(cdata, frame);
69 _current_frame = frame;
73 int max_z = std::max(cdata->_z_size, (
int)_pages.size());
74 for (
int z = 0; z < max_z; ++z) {
75 VideoPage &page = _pages[z];
76 if (!page._color.is_from_file() || !page._alpha.is_from_file()) {
77 do_update_frame(cdata, frame, z);
81 _last_frame_update = this_frame;
95 make_copy_impl()
const {
97 PT(OpenCVTexture) copy =
new OpenCVTexture(get_name());
99 copy->do_assign(cdata_copy_tex,
this, cdata_tex);
108 do_assign(Texture::CData *cdata_tex,
const OpenCVTexture *copy,
109 const Texture::CData *cdata_copy_tex) {
110 VideoTexture::do_assign(cdata_tex, copy, cdata_copy_tex);
111 _pages = copy->_pages;
124 from_camera(
int camera_index,
int z,
int alpha_file_channel,
127 if (!do_reconsider_z_size(cdata, z, options)) {
130 nassertr(z >= 0 && z < cdata->_z_size,
false);
132 cdata->_alpha_file_channel = alpha_file_channel;
134 VideoPage &page = do_modify_page(cdata, z);
135 if (alpha_file_channel == 0) {
138 if (!page._color.from_camera(camera_index)) {
142 if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
149 if (!page._alpha.from_camera(camera_index)) {
153 if (!do_reconsider_video_properties(cdata, page._alpha, 1, z, options)) {
157 do_set_format(cdata, F_alpha);
160 cdata->_loaded_from_image =
true;
161 clear_current_frame();
162 do_update_frame(cdata, 0);
171 OpenCVTexture::VideoPage &OpenCVTexture::
172 do_modify_page(
const Texture::CData *cdata,
int z) {
173 nassertr(z < cdata->_z_size, _pages[0]);
174 while (z >= (
int)_pages.size()) {
175 _pages.push_back(VideoPage());
185 do_reconsider_video_properties(Texture::CData *cdata,
186 const OpenCVTexture::VideoStream &stream,
187 int num_components,
int z,
189 double frame_rate = 0.0f;
192 if (stream.is_from_file()) {
193 frame_rate = cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FPS);
194 num_frames = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_COUNT);
195 if (vision_cat.is_debug()) {
197 <<
"Loaded " << stream._filename <<
", " << num_frames <<
" frames at " 198 << frame_rate <<
" fps\n";
203 if (vision_cat.is_debug()) {
205 <<
"Loaded camera stream\n";
209 int width = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_WIDTH);
210 int height = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_HEIGHT);
214 do_adjust_this_size(cdata, x_size, y_size, get_name(),
true);
216 if (vision_cat.is_debug()) {
218 <<
"Video stream is " << width <<
" by " << height
219 <<
" pixels; fitting in texture " << x_size <<
" by " 220 << y_size <<
" texels.\n";
223 if (!do_reconsider_image_properties(cdata, x_size, y_size, num_components,
224 T_unsigned_byte, z, options)) {
228 if (cdata->_loaded_from_image &&
229 (get_video_width() != width || get_video_height() != height ||
230 get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
232 <<
"Video properties have changed for texture " << get_name()
233 <<
" level " << z <<
".\n";
237 set_frame_rate(frame_rate);
238 set_num_frames(num_frames);
239 set_video_size(width, height);
253 return new OpenCVTexture;
260 do_update_frame(Texture::CData *cdata,
int frame) {
261 int max_z = std::max(cdata->_z_size, (
int)_pages.size());
262 for (
int z = 0; z < max_z; ++z) {
263 do_update_frame(cdata, frame, z);
271 do_update_frame(Texture::CData *cdata,
int frame,
int z) {
272 if (vision_cat.is_spam()) {
274 <<
"Updating OpenCVTexture page " << z <<
"\n";
277 VideoPage &page = _pages[z];
278 if (page._color.is_valid() || page._alpha.is_valid()) {
279 do_modify_ram_image(cdata);
280 ++(cdata->_image_modified);
282 int dest_x_pitch = cdata->_num_components * cdata->_component_width;
283 int dest_y_pitch = cdata->_x_size * dest_x_pitch;
285 if (page._color.is_valid()) {
286 nassertv(get_num_components() >= 3 && get_component_width() == 1);
288 const unsigned char *r, *g, *b;
289 int x_pitch, y_pitch;
290 if (page._color.get_frame_data(frame, r, g, b, x_pitch, y_pitch)) {
291 nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
292 nassertv(!cdata->_ram_images.empty())
293 unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
295 if (cdata->_num_components == 3 && x_pitch == 3) {
297 int copy_bytes = get_video_width() * dest_x_pitch;
298 nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch));
300 for (
int y = 0; y < get_video_height(); ++y) {
301 memcpy(dest, r, copy_bytes);
302 dest += dest_y_pitch;
310 for (
int y = 0; y < get_video_height(); ++y) {
313 for (
int x = 0; x < get_video_width(); ++x) {
315 dest[dx + 1] = g[sx];
316 dest[dx + 2] = b[sx];
320 dest += dest_y_pitch;
328 if (page._alpha.is_valid()) {
329 nassertv(get_component_width() == 1);
331 const unsigned char *source[3];
332 int x_pitch, y_pitch;
333 if (page._alpha.get_frame_data(frame, source[0], source[1], source[2],
335 nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
336 nassertv(!cdata->_ram_images.empty())
337 unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
342 const unsigned char *sch = source[0];
343 if (cdata->_alpha_file_channel >= 1 && cdata->_alpha_file_channel <= 3) {
344 sch = source[cdata->_alpha_file_channel - 1];
347 for (
int y = 0; y < get_video_height(); ++y) {
350 int dx = (cdata->_num_components - 1) * cdata->_component_width;
352 for (
int x = 0; x < get_video_width(); ++x) {
357 dest += dest_y_pitch;
369 do_read_one(Texture::CData *cdata,
371 int z,
int n,
int primary_file_num_channels,
int alpha_file_channel,
374 if (record !=
nullptr) {
378 nassertr(n == 0,
false);
379 nassertr(z >= 0 && z < cdata->_z_size,
false);
381 VideoPage &page = do_modify_page(cdata, z);
382 if (!page._color.read(fullpath)) {
384 <<
"OpenCV couldn't read " << fullpath <<
" as video.\n";
387 if (!alpha_fullpath.empty()) {
388 if (!page._alpha.read(alpha_fullpath)) {
390 <<
"OpenCV couldn't read " << alpha_fullpath <<
" as video.\n";
401 if (cdata->_filename.empty()) {
402 cdata->_filename = fullpath;
403 cdata->_alpha_filename = alpha_fullpath;
406 cdata->_fullpath = fullpath;
407 cdata->_alpha_fullpath = alpha_fullpath;
410 cdata->_primary_file_num_channels = 3;
411 cdata->_alpha_file_channel = 0;
413 if (alpha_fullpath.empty()) {
415 if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
422 cdata->_alpha_file_channel = alpha_file_channel;
424 if (!do_reconsider_video_properties(cdata, page._color, 4, z, options)) {
430 if (!do_reconsider_video_properties(cdata, page._alpha, 4, z, options)) {
437 set_loaded_from_image();
438 clear_current_frame();
439 do_update_frame(cdata, 0);
448 do_load_one(Texture::CData *cdata,
449 const PNMImage &pnmimage,
const std::string &name,
451 if (z <= (
int)_pages.size()) {
452 VideoPage &page = do_modify_page(cdata, z);
457 return Texture::do_load_one(cdata, pnmimage, name, z, n, options);
464 register_with_read_factory() {
480 OpenCVTexture::VideoStream::
491 OpenCVTexture::VideoStream::
492 VideoStream(
const OpenCVTexture::VideoStream ©) :
498 if (copy.is_valid()) {
499 if (copy.is_from_file()) {
500 read(copy._filename);
502 from_camera(copy._camera_index);
510 OpenCVTexture::VideoStream::
530 bool OpenCVTexture::VideoStream::
531 get_frame_data(
int frame,
532 const unsigned char *&r,
533 const unsigned char *&g,
534 const unsigned char *&b,
535 int &x_pitch,
int &y_pitch) {
536 nassertr(is_valid(),
false);
538 if (is_from_file() && _next_frame != frame) {
539 cvSetCaptureProperty(_capture, CV_CAP_PROP_POS_FRAMES, frame);
542 _next_frame = frame + 1;
543 IplImage *image = cvQueryFrame(_capture);
544 if (image ==
nullptr) {
548 r = (
const unsigned char *)image->imageData;
552 y_pitch = image->widthStep;
554 if (image->dataOrder == 1) {
558 g = r + image->height * y_pitch;
559 b = g + image->height * y_pitch;
562 if (image->origin == 0) {
567 r += (image->height - 1) * y_pitch;
568 g += (image->height - 1) * y_pitch;
569 b += (image->height - 1) * y_pitch;
580 bool OpenCVTexture::VideoStream::
585 _capture = cvCaptureFromFile(os_specific.c_str());
586 if (_capture ==
nullptr) {
589 _filename = filename;
597 bool OpenCVTexture::VideoStream::
598 from_camera(
int camera_index) {
601 _capture = cvCaptureFromCAM(camera_index);
602 if (_capture ==
nullptr) {
605 _camera_index = camera_index;
612 void OpenCVTexture::VideoStream::
614 if (_capture !=
nullptr) {
615 cvReleaseCapture(&_capture);
623 #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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Specifies parameters that may be passed to the loader.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_frame_count
Returns the number of times tick() has been called since the ClockObject was created, or since it was last reset.
The name of a file, such as a texture file or an Egg file.
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...