Ask Your Question

Revision history [back]

Problem reading in image correctly

For https://gist.github.com/promach/9d185d35a6e6db0da10992a19c36f754#file-host-cpp-L172 or line 172 of the following coding , why am I getting rgb_stream[STREAM_WIDTH] equals to 192, while all other entries of the array are equal to zero ?

// g++ -g host.cpp -o host `pkg-config --cflags --libs opencv`

#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>      // std::ifstream, std::ofstream
#include <string>
#include <sys/wait.h>
#include <errno.h>
#include <cmath>

using namespace cv;
using namespace std;

#define LOOPBACK 1
//#define RGB2YUV 1

unsigned int image_width;
unsigned int image_height;

const unsigned int CHNL_NUM = 3;
const unsigned int RED_CHNL = 0;
const unsigned int GREEN_CHNL = 1;
const unsigned int BLUE_CHNL = 2;

const unsigned int STREAM_WIDTH = 128; 
const unsigned int NUM_OF_BITS_PER_BYTE = 8;

const unsigned int PIXEL_VALUE_RANGE = 8; // number of bits occupied by [R, G, B] or [Y, U, V] respectively (8-bit unsigned integer for each components) , https://docs.microsoft.com/en-us/windows-hardware/drivers/display/yuv-rgb-data-range-conversions
const unsigned int NUM_OF_COMPONENTS_IN_A_PIXEL = 3; // input: [R, G, B]     output:[Y, U, V]

const unsigned int PIXEL_NUM_THAT_FITS_STREAM_WIDTH = 5;  // 128-bit stream can at most fits 5 pixels ((PIXEL_NUM_THAT_FITS_STREAM_WIDTH*NUM_OF_COMPONENTS_IN_A_PIXEL*PIXEL_VALUE_RANGE) bits = 120 bits), each pixels contains R, G, B which are encoded in 8 bits for each of the three color components

struct RGB_packet{
  uint8_t R,G,B;
};

struct YUV_packet{
  uint8_t Y,U,V;
};


struct YUV_packet* rgb2yuv(struct RGB_packet rgb_input)  // convert rgb to yuv
{  

    uint8_t red = rgb_input.R;
    uint8_t green = rgb_input.G;
    uint8_t blue = rgb_input.B;

    struct YUV_packet *yuv_result;

    uint8_t Y = yuv_result->Y;
    uint8_t U = yuv_result->U;
    uint8_t V = yuv_result->V;

    // https://www.pcmag.com/encyclopedia/term/55166/yuv-rgb-conversion-formulas
    Y = (uint8_t)(0.299*red + 0.587*green + 0.114*blue);
    U = (uint8_t)(0.492*(blue-Y));
    V = (uint8_t)(0.877*(red-Y));

    return yuv_result;
}

int main(int argc, char *argv[]) {

  int fdr, fdw, rd, wr, donebytes;
  uint8_t *to_buf, *from_buf, *wr_buf, *rd_buf;
  pid_t pid;
  struct RGB_packet *tologic;
  struct YUV_packet *fromlogic;

  fdr = open("/dev/stdout", O_RDONLY);  // will change to /dev/xillybus_read_128
  fdw = open("/dev/stdin", O_WRONLY); // will change to /dev/xillybus_write_128

  if ((fdr < 0) || (fdw < 0)) {
    perror("Failed to open Xillybus device file(s)");
    exit(1);
  }

  // READ in an image file

  String imageName( "lena512color.tiff" ); // by default

  if( argc > 1)
  {
    imageName = argv[1];
  }

  Mat image;

  image = imread( imageName, IMREAD_COLOR ); // Read the file

  if( image.empty() )                      // Check for invalid input
  {
    cout <<  "Could not open or find the image" << std::endl ;
    return -1;
  }

  else
  {
    image_width = image.size().width;
    image_height = image.size().height;
  }

  namedWindow( "Original Image", CV_WINDOW_AUTOSIZE );
  imshow( "Original Image", image );

  Mat rgbchannel[CHNL_NUM];
  // The actual splitting.
  split(image, rgbchannel);

  namedWindow("Blue",CV_WINDOW_AUTOSIZE);
  imshow("Red", rgbchannel[RED_CHNL]);

  namedWindow("Green",CV_WINDOW_AUTOSIZE);
  imshow("Green", rgbchannel[GREEN_CHNL]);

  namedWindow("Red",CV_WINDOW_AUTOSIZE);
  imshow("Blue", rgbchannel[BLUE_CHNL]);

  waitKey(0);  // see all three split channels before feeding in the channel data to xillybus/RIFFA for hardware computation


  pid = fork();

  if (pid < 0) {
    perror("Failed to fork()");
    exit(1);
  }

  if (pid) {
    close(fdr);

    vector<RGB_packet> vTo(sizeof(struct RGB_packet) * image_width * image_height);  // lena.tiff is sized as 512*512*3

    tologic = vTo.data();

    if (!tologic) {
      fprintf(stderr, "Failed to allocate memory\n");
      exit(1);
    }

    tologic->R = *(rgbchannel[RED_CHNL].data);
    tologic->G = *(rgbchannel[GREEN_CHNL].data);
    tologic->B = *(rgbchannel[BLUE_CHNL].data);

    to_buf = (uint8_t *) tologic;
    donebytes = 0;
    unsigned int if_index = 0;
    while (donebytes < sizeof(struct RGB_packet) * image_width * image_height) 
    {
      if(((sizeof(struct RGB_packet) * image_width * image_height)-donebytes) >= (STREAM_WIDTH/NUM_OF_BITS_PER_BYTE))
      {
        // arrange the five pixels in the format as in https://i.imgur.com/mdJwk7J.png
        if_index++; printf("if_index = %d\n\r", if_index);
        uint8_t rgb_stream[STREAM_WIDTH+1];  // contains 5 pixels

        rgb_stream[STREAM_WIDTH+1] = '\0';
        rgb_stream[0] = 0;  // remember that the top 8 bits of the 128-bits stream are ignored

        for(unsigned int k=1; (k+NUM_OF_COMPONENTS_IN_A_PIXEL-1)<=STREAM_WIDTH; k=k+NUM_OF_COMPONENTS_IN_A_PIXEL)   
        {
            rgb_stream[k] = tologic[k+donebytes].R;
            rgb_stream[k+1] = tologic[k+donebytes].G;
            rgb_stream[k+NUM_OF_COMPONENTS_IN_A_PIXEL-1] = tologic[k+donebytes].B;
        }

        for(unsigned int j=0; j<=STREAM_WIDTH; j++)     
        {
            printf("rgb_stream[%d] = %d\n\r", j, rgb_stream[j]);
        }

        wr_buf = rgb_stream;

        wr = write(fdw, wr_buf, STREAM_WIDTH/NUM_OF_BITS_PER_BYTE);  
      }
      else  // the remaining pixels do not fill all five pixel slots for a 128-bit stream
      {
        //wr_buf = ;

        wr = write(fdw, wr_buf, sizeof(struct RGB_packet) * image_width * image_height - donebytes);
      }

      if ((wr < 0) && (errno == EINTR))
        continue;

      if (wr <= 0) {
        perror("write() failed");
        exit(1);
      }

      donebytes += wr;
    }



sleep(1); // Let debug output drain (if used)

    close(fdw);

    return 0;
  } 

  else {
    close(fdw);

    vector<YUV_packet> vFrom(sizeof(struct YUV_packet) * image_width * image_height);

    fromlogic = vFrom.data();

    if (!fromlogic) {
      fprintf(stderr, "Failed to allocate memory\n");
      exit(1);
    }

    from_buf = (uint8_t *) fromlogic;
    donebytes = 0;

    while (donebytes < sizeof(struct YUV_packet) * image_width * image_height) {

      if(((sizeof(struct RGB_packet) * image_width * image_height)-donebytes) >= PIXEL_NUM_THAT_FITS_STREAM_WIDTH)
      {
        rd = read(fdr, from_buf + donebytes, STREAM_WIDTH/NUM_OF_BITS_PER_BYTE); 
      }      
      else // the remaining pixels do not fill all five pixel slots for a 128-bit stream
      {
        rd = read(fdr, from_buf + donebytes, sizeof(struct YUV_packet) * image_width * image_height - donebytes);
      }

      if ((rd < 0) && (errno == EINTR))
        continue;

      if (rd < 0) {
        perror("read() failed");
        exit(1);
      }

      if (rd == 0) {
        fprintf(stderr, "Reached read EOF!? Should never happen.\n");
        exit(0);
      }

      donebytes += rd;
    }

    for (unsigned int i = 0; i < (image_width * image_height); i++)  // check the perfomance of hardware with respect to software computation
    {
    #ifdef LOOPBACK
        if( (tologic[i].R == fromlogic[i].Y) ||
            (tologic[i].G == fromlogic[i].U) ||
            (tologic[i].B == fromlogic[i].V) )
    #elif RGB2YUV
        if( (abs(rgb2yuv(tologic[i])->Y - fromlogic[i].Y) > 1) ||
            (abs(rgb2yuv(tologic[i])->U - fromlogic[i].U) > 1) ||
            (abs(rgb2yuv(tologic[i])->V - fromlogic[i].V) > 1) ) // rgb2yuv conversion hardware tolerance fails by more than 1 compared to software computation
    #endif
        {
            printf("R:%d G:%d B:%d \n", tologic[i].R, tologic[i].G, tologic[i].B);
            printf("Y:%d U:%d V:%d \n", fromlogic[i].Y, fromlogic[i].U, fromlogic[i].V);
        }
    }

    sleep(1); // Let debug output drain (if used)

    close(fdr);

    return 0;
  }
}