skip to Main Content

I have an iOS app that analyzes video from the camera using OpenCV.

The video that is being displayed is in BGR.

After upgrading from Xcode 13 to 14, the video has stopped being displayed, and this has appeared in the logs:

CGImageCreate: invalid image byte order info for bitsPerPixel != 32 = 16384

After debugging, it seems that when I change the frames from BGR to Gray and also to RGBA, it works:

cvtColor( frame, frame, COLOR_BGR2GRAY ); // works

cvtColor( frame, frame, COLOR_BGR2RGBA ); // works

But I don’t want to the video to be gray, and the RGBA video didn’t look right.

When I tried displaying in RGB it crashed:

cvtColor( frame, frame, COLOR_BGR2RGB ); // didn't work

What can be the issue? What can be a fix?

2

Answers


  1. I Dont know much about Xcode14, but when you change the color space using cvtColor function, it changes the number of channels in the image. The BGR color space has 3 channels (blue, green and red) while Gray has only 1 channel and RGBA has 4 channels (red, green, blue, and alpha).

    In the current case, changing the color space to Gray or RGBA works because these color spaces have a byte order that is compatible with CGImageCreate. However, when you try to change the color space to RGB, the byte order becomes incompatible, which leads to the crash.

    Some solutions(only my personal opinion):

    1. To use cv::flip to change the byte order of the image before displaying it:
    cvtColor(frame, frame, COLOR_BGR2RGB);
    cv::flip(frame, frame, 0); // flip vertically
    cv::imshow("Video", frame);
    

    This will flip the rows of the image vertically, effectively changing the byte order to a compatible format for CGImageCreate.

    1. To use cv::cvtColor with COLOR_BGR2BGRA instead of COLOR_BGR2RGBA. This will add an alpha channel to your BGR image while preserving the original byte order:
    cvtColor(frame, frame, COLOR_BGR2BGRA);
    cv::imshow("Video", frame);
    

    I hope that helps!!

    Login or Signup to reply.
  2. It crashes because the byte order is not compatible with the expected format. Manually rearrange the blue and red channels of each pixel in the BGR image.

    Possible solutions:

    1- Convert the BGR image to BGRA and then rearrange the channels to match the RGB order. The fromTo array specifies the channel rearrangement from BGR to RGB.

    cvtColor(frame, frame, COLOR_BGR2BGRA);
    
    // Rearrange the color channels to match RGB order
    cv::Mat frameRGB(frame.rows, frame.cols, CV_8UC3);
    // Reorder channels from BGR to RGB
    int fromTo[] = {0, 2, 1, 1, 2, 0};
    mixChannels(&frame, 1, &frameRGB, 1, fromTo, 3);
    

    2- Split the BGR channels, swap the blue and red channels, and then merge them to create an RGB image. This approach should work as long as the original image is indeed in the BGR color space. By manually swapping the channels, you can bypass any potential issues related to byte order information.

    // Split the BGR channels
    std::vector<cv::Mat> bgrChannels(3);
    cv::split(frame, bgrChannels);
    
    // Swap the blue and red channels
    cv::Mat rgbFrame;
    std::vector<cv::Mat> rgbChannels = {bgrChannels[2], bgrChannels[1], bgrChannels[0]};
    cv::merge(rgbChannels, rgbFrame);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search