space_voyager
space_voyager

Reputation: 2034

Assign HSV values to specific pixels?

I'm looking for an efficient way of assigning values to an element of a 3-channel matrix. In particular, I need to assign HSV values to elements of a 2D cv::Mat which is initialized as follows:

cv::Mat clusterImage(height,width,CV_8UC3,cv::Scalar(0,0,0));

For this matrix, how do I set the pixel in row i and column j to an HSV value (H=59, S=255, V=255), as efficiently as possible?

My current method (complete code) is below. My fear is that splitting a matrix into channels, editing those channels and then merging them back together is not very efficient - especially since I need to do it in a loop, preferably at 30Hz and above. Does a more efficient method exist?

#include <vector>
#include <stdlib.h>
#include <iostream>

#include <opencv/cv.h>
#include <opencv/highgui.h>

using namespace std;

int main() {
  int height = 480;
  int width = 640;

  cv::Mat clusterImage(height,width,CV_8UC3,cv::Scalar(0,0,0));
  vector<cv::Mat> channels(3);

  // split the channels
  split(clusterImage, channels);

  // modify the channels
  vector<int> i;
  vector<int> j;
  int numberOfDots = 1000;

  for (int k=0; k<numberOfDots; k++) {
    i.push_back(rand() % height + 1);
    j.push_back(rand() % width + 1);
  }

  for (int k=0; k<numberOfDots; k++) {
    channels[0].at<unsigned char>(i[k],j[k]) = 59;
    channels[1].at<unsigned char>(i[k],j[k]) = 255;
    channels[2].at<unsigned char>(i[k],j[k]) = 255;
  }

  // merge channels
  merge(channels, clusterImage);

  // convert to RGB and draw
  cv::cvtColor(clusterImage, clusterImage, CV_HSV2BGR);
  imshow("test_window", clusterImage);

  cv::waitKey(0);

  return 0;
}

Upvotes: 0

Views: 458

Answers (2)

MeiH
MeiH

Reputation: 1865

This code would be my choice:

  int height = 480;
  int width = 640;

  cv::Mat clusterImage(height,width,CV_8UC3,cv::Scalar(0,0,0));

  int numberOfDots = 1000;
  int i , j;

  for (int k=0; k<numberOfDots; k++) 
  {
    i = rand() % height ; j = rand() % width ;

    clusterImage.at<Vec3b>(i , j )[0] = 59;
    clusterImage.at<Vec3b>(i , j )[1] = 255;
    clusterImage.at<Vec3b>(i , j )[2] = 255;
  }

  // convert to RGB and draw
  cv::cvtColor(clusterImage, clusterImage, CV_HSV2BGR);
  imshow("test_window", clusterImage);

  cv::waitKey(0);

Upvotes: 1

Malcolm McLean
Malcolm McLean

Reputation: 6404

Yes, you can make this a lot more efficient.

You can assign to a CV::Mat more or less directly. Assuming your system is underlying RGB, simply set up a CV::Mat of width and hight and with three or four channels (often a dummy alpha makes things a bit faster). Then look up the rgb values for HSV 59, 255, 255 - there are plenty of formulae - and set them directly. I think you can use the "at" member function but that's based on a casual glance at the CV::Mat interface.

Finally, you can get rid of the vectors i and j of the dot x, y co-cordinates, assuming you don't need them later on. Just loop on numberOfDots and generatate two temporary random numbers

Upvotes: 1

Related Questions