26 #if defined(OPENCV_VER_3) 28 #include <opencv2/core.hpp> 29 #include <opencv2/videoio/videoio_c.h> 32 #elif defined(OPENCV_VER_23) 34 #include <opencv2/core/core.hpp> 35 #include <opencv2/highgui/highgui.hpp> 44 #endif // OPENCV_VER_3 52 OpenCVTexture(
const std::string &name) :
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 = std::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;
101 make_copy_impl()
const {
103 PT(OpenCVTexture) copy =
new OpenCVTexture(get_name());
105 copy->do_assign(cdata_copy_tex,
this, cdata_tex);
114 do_assign(Texture::CData *cdata_tex,
const OpenCVTexture *copy,
115 const Texture::CData *cdata_copy_tex) {
116 VideoTexture::do_assign(cdata_tex, copy, cdata_copy_tex);
117 _pages = copy->_pages;
130 from_camera(
int camera_index,
int z,
int alpha_file_channel,
133 if (!do_reconsider_z_size(cdata, z, options)) {
136 nassertr(z >= 0 && z < cdata->_z_size,
false);
138 cdata->_alpha_file_channel = alpha_file_channel;
140 VideoPage &page = do_modify_page(cdata, z);
141 if (alpha_file_channel == 0) {
144 if (!page._color.from_camera(camera_index)) {
148 if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
155 if (!page._alpha.from_camera(camera_index)) {
159 if (!do_reconsider_video_properties(cdata, page._alpha, 1, z, options)) {
163 do_set_format(cdata, F_alpha);
166 cdata->_loaded_from_image =
true;
167 clear_current_frame();
168 do_update_frame(cdata, 0);
177 OpenCVTexture::VideoPage &OpenCVTexture::
178 do_modify_page(
const Texture::CData *cdata,
int z) {
179 nassertr(z < cdata->_z_size, _pages[0]);
180 while (z >= (
int)_pages.size()) {
181 _pages.push_back(VideoPage());
191 do_reconsider_video_properties(Texture::CData *cdata,
192 const OpenCVTexture::VideoStream &stream,
193 int num_components,
int z,
195 double frame_rate = 0.0f;
198 if (stream.is_from_file()) {
199 frame_rate = cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FPS);
200 num_frames = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_COUNT);
201 if (vision_cat.is_debug()) {
203 <<
"Loaded " << stream._filename <<
", " << num_frames <<
" frames at " 204 << frame_rate <<
" fps\n";
209 if (vision_cat.is_debug()) {
211 <<
"Loaded camera stream\n";
215 int width = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_WIDTH);
216 int height = (int)cvGetCaptureProperty(stream._capture, CV_CAP_PROP_FRAME_HEIGHT);
220 do_adjust_this_size(cdata, x_size, y_size, get_name(),
true);
222 if (vision_cat.is_debug()) {
224 <<
"Video stream is " << width <<
" by " << height
225 <<
" pixels; fitting in texture " << x_size <<
" by " 226 << y_size <<
" texels.\n";
229 if (!do_reconsider_image_properties(cdata, x_size, y_size, num_components,
230 T_unsigned_byte, z, options)) {
234 if (cdata->_loaded_from_image &&
235 (get_video_width() != width || get_video_height() != height ||
236 get_num_frames() != num_frames || get_frame_rate() != frame_rate)) {
238 <<
"Video properties have changed for texture " << get_name()
239 <<
" level " << z <<
".\n";
243 set_frame_rate(frame_rate);
244 set_num_frames(num_frames);
245 set_video_size(width, height);
259 return new OpenCVTexture;
266 do_update_frame(Texture::CData *cdata,
int frame) {
267 int max_z = std::max(cdata->_z_size, (
int)_pages.size());
268 for (
int z = 0; z < max_z; ++z) {
269 do_update_frame(cdata, frame, z);
277 do_update_frame(Texture::CData *cdata,
int frame,
int z) {
278 if (vision_cat.is_spam()) {
280 <<
"Updating OpenCVTexture page " << z <<
"\n";
283 VideoPage &page = _pages[z];
284 if (page._color.is_valid() || page._alpha.is_valid()) {
285 do_modify_ram_image(cdata);
286 ++(cdata->_image_modified);
288 int dest_x_pitch = cdata->_num_components * cdata->_component_width;
289 int dest_y_pitch = cdata->_x_size * dest_x_pitch;
291 if (page._color.is_valid()) {
292 nassertv(get_num_components() >= 3 && get_component_width() == 1);
294 const unsigned char *r, *g, *b;
295 int x_pitch, y_pitch;
296 if (page._color.get_frame_data(frame, r, g, b, x_pitch, y_pitch)) {
297 nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
298 nassertv(!cdata->_ram_images.empty())
299 unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
301 if (cdata->_num_components == 3 && x_pitch == 3) {
303 int copy_bytes = get_video_width() * dest_x_pitch;
304 nassertv(copy_bytes <= dest_y_pitch && copy_bytes <= abs(y_pitch));
306 for (
int y = 0; y < get_video_height(); ++y) {
307 memcpy(dest, r, copy_bytes);
308 dest += dest_y_pitch;
316 for (
int y = 0; y < get_video_height(); ++y) {
319 for (
int x = 0; x < get_video_width(); ++x) {
321 dest[dx + 1] = g[sx];
322 dest[dx + 2] = b[sx];
326 dest += dest_y_pitch;
334 if (page._alpha.is_valid()) {
335 nassertv(get_component_width() == 1);
337 const unsigned char *source[3];
338 int x_pitch, y_pitch;
339 if (page._alpha.get_frame_data(frame, source[0], source[1], source[2],
341 nassertv(get_video_width() <= cdata->_x_size && get_video_height() <= cdata->_y_size);
342 nassertv(!cdata->_ram_images.empty())
343 unsigned char *dest = cdata->_ram_images[0]._image.p() + do_get_expected_ram_page_size(cdata) * z;
348 const unsigned char *sch = source[0];
349 if (cdata->_alpha_file_channel >= 1 && cdata->_alpha_file_channel <= 3) {
350 sch = source[cdata->_alpha_file_channel - 1];
353 for (
int y = 0; y < get_video_height(); ++y) {
356 int dx = (cdata->_num_components - 1) * cdata->_component_width;
358 for (
int x = 0; x < get_video_width(); ++x) {
363 dest += dest_y_pitch;
375 do_read_one(Texture::CData *cdata,
377 int z,
int n,
int primary_file_num_channels,
int alpha_file_channel,
380 if (record !=
nullptr) {
384 nassertr(n == 0,
false);
385 nassertr(z >= 0 && z < cdata->_z_size,
false);
387 VideoPage &page = do_modify_page(cdata, z);
388 if (!page._color.read(fullpath)) {
390 <<
"OpenCV couldn't read " << fullpath <<
" as video.\n";
393 if (!alpha_fullpath.empty()) {
394 if (!page._alpha.read(alpha_fullpath)) {
396 <<
"OpenCV couldn't read " << alpha_fullpath <<
" as video.\n";
407 if (cdata->_filename.empty()) {
408 cdata->_filename = fullpath;
409 cdata->_alpha_filename = alpha_fullpath;
412 cdata->_fullpath = fullpath;
413 cdata->_alpha_fullpath = alpha_fullpath;
416 cdata->_primary_file_num_channels = 3;
417 cdata->_alpha_file_channel = 0;
419 if (alpha_fullpath.empty()) {
421 if (!do_reconsider_video_properties(cdata, page._color, 3, z, options)) {
428 cdata->_alpha_file_channel = alpha_file_channel;
430 if (!do_reconsider_video_properties(cdata, page._color, 4, z, options)) {
436 if (!do_reconsider_video_properties(cdata, page._alpha, 4, z, options)) {
443 set_loaded_from_image();
444 clear_current_frame();
445 do_update_frame(cdata, 0);
454 do_load_one(Texture::CData *cdata,
455 const PNMImage &pnmimage,
const std::string &name,
457 if (z <= (
int)_pages.size()) {
458 VideoPage &page = do_modify_page(cdata, z);
463 return Texture::do_load_one(cdata, pnmimage, name, z, n, options);
470 register_with_read_factory() {
486 OpenCVTexture::VideoStream::
497 OpenCVTexture::VideoStream::
498 VideoStream(
const OpenCVTexture::VideoStream ©) :
504 if (copy.is_valid()) {
505 if (copy.is_from_file()) {
506 read(copy._filename);
508 from_camera(copy._camera_index);
516 OpenCVTexture::VideoStream::
536 bool OpenCVTexture::VideoStream::
537 get_frame_data(
int frame,
538 const unsigned char *&r,
539 const unsigned char *&g,
540 const unsigned char *&b,
541 int &x_pitch,
int &y_pitch) {
542 nassertr(is_valid(),
false);
544 if (is_from_file() && _next_frame != frame) {
545 cvSetCaptureProperty(_capture, CV_CAP_PROP_POS_FRAMES, frame);
548 _next_frame = frame + 1;
549 IplImage *image = cvQueryFrame(_capture);
550 if (image ==
nullptr) {
554 r = (
const unsigned char *)image->imageData;
558 y_pitch = image->widthStep;
560 if (image->dataOrder == 1) {
564 g = r + image->height * y_pitch;
565 b = g + image->height * y_pitch;
568 if (image->origin == 0) {
573 r += (image->height - 1) * y_pitch;
574 g += (image->height - 1) * y_pitch;
575 b += (image->height - 1) * y_pitch;
586 bool OpenCVTexture::VideoStream::
591 _capture = cvCaptureFromFile(os_specific.c_str());
592 if (_capture ==
nullptr) {
595 _filename = filename;
603 bool OpenCVTexture::VideoStream::
604 from_camera(
int camera_index) {
607 _capture = cvCaptureFromCAM(camera_index);
608 if (_capture ==
nullptr) {
611 _camera_index = camera_index;
618 void OpenCVTexture::VideoStream::
620 if (_capture !=
nullptr) {
621 cvReleaseCapture(&_capture);
629 #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,...
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...