0

Basically, I am trying to read a live feed from a webcam, split this feed into a grid of 10x10 (100 total) blocks and re-build the video frame in a random order. With this new order of blocks making up a frame I am trying to apply effects to each block depending on its position (for example: greyscale, gausian blur etc). The above is okay. The problem I am experiencing is coming from trying to rebuild the frame with blocks which are both RGB and greyscale being that one has three channels the other has one, giving the following error:

error: (-215) channels() == CV_MAT_CN(dtype) in function copyTo

I've encountered this situation before and in the past have resolved it by duplicating the single grey-scale channel three times and merging together. This time round however it doesn't seem to be solving the problem. I should also point out I am quite new to OpenCV so I could be confusing something trivial. I expect the problem is in the second case of the switch statement:

#include <imgproc_c.h>
#include <iostream>

using namespace cv;

int main( int argc, char** argv ) {
    namedWindow( "Example2_10", WINDOW_AUTOSIZE );
    VideoCapture cap;
    if (argc==1) {
        cap.open(-1); //0
     } else {
        cap.open(argv[1]);
     }
     if( !cap.isOpened() ) {  // check if we succeeded
          std::cerr << "Couldn't open capture." << std::endl;
          return -1;
     }

     int frameWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
     int frameHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
     cv::Size sb_size(frameWidth/10, frameHeight/10);

     Mat frame, img_gry, img_gry_color, img_cny_color, img_cny, img_join,     img_flip, temp, img_effect;
     vector<Mat> img_gry_vec;
     vector<Mat> img_cny_vec;

     int n_cols = 10;
     int n_rows = 10;

     //Create multidimensional array of key pair values for positional data
     std::pair<int, int> posIndex[100];

     //Populate positional array with positions of every possible frame block
     int counter = 0;
     for(int i = 0; i < frameWidth; i += sb_size.width){
         for(int j = 0; j < frameHeight; j += sb_size.height){
             posIndex[counter] = std::make_pair(i, j);
             counter++;
          }
       }

    //Random shuffle positional array so as to provide random structure for compilation
    std::random_shuffle(&posIndex[0], &posIndex[100]);

    for(;;) {
      cap >> frame;
      if( frame.empty() )
      break;

      //Create empty grid to be populated with blocks
      Mat3b grid(n_rows * sb_size.height, n_cols * sb_size.width, Vec3b(0,0,0));

    //Initialise row/column  and effect counters.
    int rowCounter = 0;
    int colCounter = 0;
    int blockIndex = 0;
    int effectIndex = 0;

    for(int i = 0; i < frameWidth; i += sb_size.width){//iterate columns
         colCounter = 0; //Reset column number on new row
         rowCounter++; //Count row number
         effectIndex++; //reset effect counter to equal row number on new row.

        if(effectIndex == 6){
            effectIndex = 1;
        }

        for(int j = 0; j < frameHeight; j += sb_size.height){//iterate rows
           colCounter++; //Count column number: 0 - 9
           blockIndex++; //Count block index: 0 - 99

           //Get block position from shuffled positional array to temporary storage.
           temp = Mat(frame, Rect(posIndex[blockIndex].first, posIndex[blockIndex].second, sb_size.width, sb_size.height)).clone();
           Rect roi(i, j, sb_size.width, sb_size.height);//Get region of interest

           effectIndex++;
           //if effect index reaches five, reset to one
           if(effectIndex == 6){
              effectIndex = 1;
           }

           //Determine which effect to apply based on effect index
           switch(effectIndex){
              case 1:
                  //Copy to grid at correct roi with no effect applied.
                  temp.copyTo(grid(roi));
              break;

              case 2:
                  cvtColor(temp, img_gry, COLOR_BGR2GRAY);
                  img_gry_vec.push_back(img_gry);
                  img_gry_vec.push_back(img_gry);
                  img_gry_vec.push_back(img_gry);
                  cv::merge(img_gry_vec, img_gry_color);
                  img_gry_color.copyTo(grid(roi));
              break;

              case 3:
                  temp.copyTo(grid(roi));
              break;

              case 4:
                   GaussianBlur( temp, img_effect, Size(5, 5), 3, 3 );
                  img_effect.copyTo(grid(roi));
              break;

              case 5:
                  temp.copyTo(grid(roi));
              break;
          }
      }
   }

   imshow( "Example3", grid);

   img_gry_vec.clear();

   if( cv::waitKey(33) >= 0 )
      break;
    }
  return 0;
}

The program runs as expected without the greyscale applied. Any help or pointers is much appreciated.

avidfeed
  • 11
  • 2
  • Small addition, if I try to display the greyscale blocks directly in the imshow() I get a: error: -15 Source images must have 1, 3 or 4 channels. As far as I can tell, it does have three channels... – avidfeed Mar 04 '17 at 16:57
  • Okay, so I was clearing my container vector outwith the loop. Problem solved. Bit embarrassing for a first question. – avidfeed Mar 04 '17 at 17:04
  • Nothing to be ashamed of. As long as you respect other people's time by putting effort into explaining your problem, you're still better than huge part of the people asking questions here. – Michał Gacka Mar 04 '17 at 20:59

0 Answers0