0
votes

I am using openCV 3.1.0 (I have tried with 2.4.9, with same problem). I want to output a HSV mat to jpeg:

// .. Getting JPEG content into memory
// JPEG to mat
Mat imgBuf=Mat(1, jpegContent, CV_8UC3, jpegSize);
Mat imgMat=imdecode(imgBuf, CV_LOAD_IMAGE_COLOR);
free(jpegContent);
if(imgMat.data == NULL) {
    // Some error handling
}
// Now the JPEG is decoded and reside in imgMat
cvtColor(imgMat, imgMat, CV_BGR2HSV); // Converting to HSV
Mat tmp;
inRange(imgMat, Scalar(0, 0, 0), Scalar(8, 8, 8), tmp); // Problem goes here
cvtColor(tmp, imgMat, CV_HSV2BGR);
// Mat to JPEG
vector<uchar> buf;
imencode(".jpg", imgMat, buf, std::vector<int>());
outputJPEG=(unsigned char*)malloc(buf.size());
memcpy(outputJPEG, &buf[0], buf.size());
// ... Output JPEG

The problem is, when i do cvtColor(tmp, imgMat, CV_HSV2BGR) with inRange, my program will fail with:

OpenCV Error: Assertion failed (scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F)) in cvtColor, file /home/pi/opencv/src/opencv-3.1.0/modules/imgproc/src/color.cpp, line 8176

terminate called after throwing an instance of 'cv::Exception' what(): /home/pi/opencv/src/opencv-3.1.0/modules/imgproc/src/color.cpp:8176: error: (-215) scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) in function cvtColor

If i removed inRange, the program work just fine. I have tried to remove the cvtColor call, letting imencode to do its job, automatically converting HSV to BGR then to JPEG. This time, no more assertion failed, but i got corrupted JPEG image, as GStreamer complains:

gstrtpjpegpay.c(581): gst_rtp_jpeg_pay_read_sof (): /GstPipeline:pipeline0/GstRtpJPEGPay:rtpjpegpay0 WARNING: from element /GstPipeline:pipeline0/GstRtpJPEGPay:rtpjpegpay0: Wrong SOF length 11.

Again, removing inRange also solves this issue, it produces good JPEG data.

So, is that i am invoking inRange improperly that cause corrupted image data? If yes, what is the correct way to use inRange?

1
inRange gives you a binary matrix of type CV_8UC1. You cannot convert it to HSVMiki
It works pretty well now, thanks.Kong Chun Ho

1 Answers

1
votes

inRange produces a single channel binary matrix, i.e. a CV_8UC1 matrix with values either 0 or 255.

So you cannot convert tmp with HSV2BGR, because the source image tmp doesn't have 3 channels.

OpenCV is telling you exactly this: scn (source channels) is not 3.


Since you probably want to keep and then convert to BGR only part of the image in your range, you can:

  1. set to black everything outside the range: imgMat.setTo(Scalar(0,0,0), ~tmp);
  2. convert the resulting image to BGR: cvtColor(imgMat, imgMat, CV_HSV2BGR);