Search code examples
c++imageopengledsdk

How to get dimensions and format of EVF LiveView Image?


First off, let me post links to some similar SO questions that I found via Google. The first link does seem to have a valid answer, but it doesn't directly address my issue. The second link does directly address my issue, but the response by gdh doesn't seem to help me.

Canon LiveView: image convertion to OpenCV Mat

Canon EDSDK How can I get width and height of live view images?

What I am trying to do download images from my Canon Rebel during Live View mode using Canon's EDSDK. I'm able to open the stream and continuously download a stream of data, but where I'm getting stumped is how to convert that data into a usable image. Ultimately my goal is to upload live view images directly into an OpenGL texture via glTexSubImage2D, but I'm unclear on how to get the image bit depth, color format, and dimensions.

Allow me to post some sample code; please bear in mind that this is a stripped down example of my working code - I omit some details like starting the stream, getting the camera ref or releasing any references, and in practice the download and OpenGL calls take place on different threads.

// All my variables
EdsStreamRef evfStream = nullptr;     // evf datastream
EdsImageRef evfImg = nullptr;         // image ref
EdsCameraRef camRef = nullptr;        // camera ref
void * pData = nullptr;               // Pointer to image data
EdsUInt64 uLength( 0 );               // Size in bytes of image data
GLuint uGLTexID( 0 );                 // Handle to OpenGL texture
EdsSize imgSize{0};                   // Width, height of image
GLuint uClrFmt = GL_RGB;              // Color format of image
GLuint uClrType = GL_UNSIGNED_BYTE;   // Color data type of image

//////////////////////////////////////////////////////////////////////
// Get image from camera

// Create memory stream, init size to 1 byte for now
EdsCreateMemoryStream( 1, &evfStream );

// Create an image ref from the streawm
EdsCreateEvfImageRef( evfStream, &evfImg );

// Download the image (which I believe resizes the stream)
EdsDownloadEvfImage( camRef, evfImg );

// Get data size and pointer
EdsGetLength( evfStream, &uLength );
EdsGetPointer( evfStream, &pData );

//////////////////////////////////////////////////////////////////////
// Get image info

// This doesn't seem to be correct, using these dimensions causes a crash
EdsGetPropertyData( m_WriteImg.imgRef, kEdsPropID_Evf_CoordinateSystem, 0, sizeof( EdsSize ), &imgSize );

// How do I get these two?
uClrFmt = GL_RGB;
uClrType = GL_UNSIGNED_BYTE;

//////////////////////////////////////////////////////////////////////
// Upload to GPU

// If this is the first time, create the texture
bool bFirstTime = true;
if ( bFirstTime )
{
    //Generate the device texture and bind it
    glGenTextures( 1, &uGLTexID );
    glBindTexture( GL_TEXTURE_2D, uGLTexID );

    //Upload host texture to device
    glTexImage2D( GL_TEXTURE_2D, 0, uClrFmt, imgSize.width, imgSize.height, 0, uClrFmt, uClrType, pData );

    // Unbind
    glBindTexture( GL_TEXTURE_2D, 0 );

    bFirstTime = false;
}
// Otherwise update the existing texture
else
{
    // Bind texture
    glBindTexture( GL_TEXTURE_2D, uGLTexID );

    // Upload image
    glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, imgSize.width, imgSize.height, uClrType, uClrFmt, pData );

    // Unbind
    glBindTexture( GL_TEXTURE_2D, 0 );
}

The parts that are missing is how to get the actual image and its properties. The EDSDK sample, as well as the OpenCV related question, do provide an example of how to convert that data into a usable image, but both involve using another library to place the data into a usable image.

In the EDSDK example, GDI+ is used to create a CImage object. I can see in my debugger that the CImage created has a bit depth of 24 and dimensions of 1056x704 (or something like that), but I have no clue how that data is retrieved.

The thing that confuses me the most is that the uLength variable, which is the size in bytes of the data stream, does not stay constant (it seems to vary by a relatively small amount each time.) How is that possible if the actual image size seems to remain constant?

Anyway, any help with this issue would be appreciated. I could try and use the library based solutions, but I'm trying to keep latency as low as possible. If I can provide any more information, or if you'd like to see my actual code (in case the issue could be there), please let me know.

Thanks,

John


Solution

  • as far as I know there is no function to get the live view size and it's also not really necessary. The live view frame you download is a standard jpg so you can find out the size by reading its header. I don't know how OpenCV or OpenGL works with jpg images but I'm sure there is some function if they support reading that format. Otherwise you can use one of the many jpg libraries. The jpg compression also explains why the image size varies between frames.

    What you actually get by calling EdsGetPropertyData with kEdsPropID_Evf_CoordinateSystem is the live view coordinate system size. It's definitely not the live view size. I think it's closer to the photo size but I'm not entirely sure about that.