I have a 16-bit tiff image with no color profile (camera profile embedded) and I am trying to read its RGB values in OpenCV. However, comparing the output values to the values given when the image is opened by GIMP for example gives totally different values (GIMP being opened with keeping the image's profile option; no profile conversion). I have tried also another image studio software like CaptureOne and the result accords with GIMP differs from OpenCV output.
Not sure if reading and opening the image in OpenCV is wrong somehow, in spite of using IMREAD_UNCHANGED flag.
I have as well tried to read the image using FreeImage library but still the same result.
Here is a snippet of the code reading pixels' values in OpenCV
const float Conv16_8 = 255.f / 65535.f;
cv::Vec3d curVal;
// upperLeft/lowerRight are just some pre-defined corners for the ROI
for (int row = upperLeft.y; row <= lowerRight.y; row++) {
unsigned char* dataUCPtr = img.data + row * img.step[0];
unsigned short* dataUSPtr = (unsigned short*)dataUCPtr;
dataUCPtr += 3 * upperLeft.x;
dataUSPtr += 3 * upperLeft.x;
for (int col = upperLeft.x; col <= lowerRight.x; col++) {
if (/* some check if the pixel is valid */) {
if (img.depth() == CV_8U) {
for (int chan = 0; chan < 3; chan++) {
curVal[chan] = *dataUCPtr++;
}
}
else if (img.depth() == CV_16U) {
for (int chan = 0; chan < 3; chan++) {
curVal[chan] = (*dataUSPtr++)*Conv16_8;
}
}
avgX += curVal;
}
else {
dataUCPtr += 3;
dataUSPtr += 3;
}
}
}
and here is the image (download the image) I am reading with its RGB readouts in
CaptureOne Studio AdobeRGB:
vs OpenCV RGB (A1=white --> F1=Black):
PS1: I have tried also to change the output color space in GIMP/CaptureOne to sRGB but still the difference is almost the same, not any closer to OpenCV
PS2: I am reversing OpenCV imread channels' order before extracting the RGB values from the image COLOR_RGB2BGR
OP said:
I have a 16-bit tiff image with no color profile (camera profile embedded)
Well no, your image definitely has a color profile, and it should not be ignored. The embedded profile is as important as the numeric values of each pixel. Without a defined profile, the pixel values are somewhat meaningless.
From what I can tell, OpenCV does not linearize gamma by default... except when it does... Regardless, the gamma indicated in the profile is unique:
Now compare that to sRGB:
So the sRGB transformations can't be used.
If you are looking for performance, applying the curve via LUT is usually more efficient than a full-on color management system.
In this case, using a LUT. The following LUT was taken from the color profile, 16bit values, and 256 steps:
// Phase One TRC from color profile
profileTRC = [0x0000,0x032A,0x0653,0x097A,0x0CA0,0x0FC2,0x12DF,0x15F8,0x190C,0x1C19,0x1F1E,0x221C,0x2510,0x27FB,0x2ADB,0x2DB0,0x3079,0x3334,0x35E2,0x3882,0x3B11,0x3D91,0x4000,0x425D,0x44A8,0x46E3,0x490C,0x4B26,0x4D2F,0x4F29,0x5113,0x52EF,0x54BC,0x567B,0x582D,0x59D1,0x5B68,0x5CF3,0x5E71,0x5FE3,0x614A,0x62A6,0x63F7,0x653E,0x667B,0x67AE,0x68D8,0x69F9,0x6B12,0x6C23,0x6D2C,0x6E2D,0x6F28,0x701C,0x710A,0x71F2,0x72D4,0x73B2,0x748B,0x755F,0x762F,0x76FC,0x77C6,0x788D,0x7951,0x7A13,0x7AD4,0x7B93,0x7C51,0x7D0F,0x7DCC,0x7E8A,0x7F48,0x8007,0x80C8,0x8189,0x824C,0x8310,0x83D5,0x849B,0x8562,0x862B,0x86F4,0x87BF,0x888A,0x8956,0x8A23,0x8AF2,0x8BC0,0x8C90,0x8D61,0x8E32,0x8F04,0x8FD7,0x90AA,0x917E,0x9252,0x9328,0x93FD,0x94D3,0x95AA,0x9681,0x9758,0x9830,0x9908,0x99E1,0x9ABA,0x9B93,0x9C6C,0x9D45,0x9E1F,0x9EF9,0x9FD3,0xA0AD,0xA187,0xA260,0xA33A,0xA414,0xA4EE,0xA5C8,0xA6A1,0xA77B,0xA854,0xA92D,0xAA05,0xAADD,0xABB5,0xAC8D,0xAD64,0xAE3B,0xAF11,0xAFE7,0xB0BC,0xB191,0xB265,0xB339,0xB40C,0xB4DE,0xB5B0,0xB680,0xB750,0xB820,0xB8EE,0xB9BC,0xBA88,0xBB54,0xBC1F,0xBCE9,0xBDB1,0xBE79,0xBF40,0xC005,0xC0CA,0xC18D,0xC24F,0xC310,0xC3D0,0xC48F,0xC54D,0xC609,0xC6C5,0xC780,0xC839,0xC8F2,0xC9A9,0xCA60,0xCB16,0xCBCA,0xCC7E,0xCD31,0xCDE2,0xCE93,0xCF43,0xCFF2,0xD0A0,0xD14D,0xD1FA,0xD2A5,0xD350,0xD3FA,0xD4A3,0xD54B,0xD5F2,0xD699,0xD73E,0xD7E3,0xD887,0xD92B,0xD9CE,0xDA6F,0xDB11,0xDBB1,0xDC51,0xDCF0,0xDD8F,0xDE2C,0xDEC9,0xDF66,0xE002,0xE09D,0xE138,0xE1D2,0xE26B,0xE304,0xE39C,0xE434,0xE4CB,0xE562,0xE5F8,0xE68D,0xE722,0xE7B7,0xE84B,0xE8DF,0xE972,0xEA04,0xEA97,0xEB29,0xEBBA,0xEC4B,0xECDC,0xED6C,0xEDFC,0xEE8B,0xEF1A,0xEFA9,0xF038,0xF0C6,0xF154,0xF1E1,0xF26F,0xF2FC,0xF388,0xF415,0xF4A1,0xF52D,0xF5B9,0xF645,0xF6D0,0xF75B,0xF7E6,0xF871,0xF8FC,0xF987,0xFA11,0xFA9B,0xFB26,0xFBB0,0xFC3A,0xFCC4,0xFD4E,0xFDD7,0xFE61,0xFEEB,0xFF75,0xFFFF]
If a matching array of the linearized values was needed, it would be
[0x0000,0x0101,0x0202,0x0303,0x0404....
But such an array is not neded for most uses, as the index value of the PhaseOne TRC array directly relates to the linear value.
I.e. phaseOneTRC[0x80] is 0xAD64
and the linear value is 0x80 * 0x101.
It turned out, it is all about having, loading and applying the proper ICC profile on the cv::Mat data. To do that one must use a color management engine along side OpenCV such as LittleCMS.
I am writing an improved Perlin noise (I don't really understand simplex noise) terrain generator for C, and I am practically finished with the alpha build. However, there is one thing holding me back: actually saving the stupid image. I recruited MagickWand to help me solve the problem of PNG creation, and it looks like a nice implementation on the whole, with tons of useful features etc., but there is very little documentation on the whole thing. No tutorials, really, just a bunch of lists of functions and some example programs. Here is my code so far, based on this:
EDIT: Cut out a bunch of irrelevant code.
#include <stdio.h>
#include <stdlib.h>
#include "mt.h"
#include "diamondsquare.h"
#include "/Library/Frameworks/libWand.framework/Versions/6.3.0/Headers/wand/MagickWand.h"
int main () {
unsigned long seed = 0, x = 0, y = 0, initial = 0, range = 0;
int smooth = 0, fail = 1, index1 = 0, index2 = 0, exception = 0;
char flagchar1 = 'n';
// Some imperative code. Not relevant.
image *ConstituteImage(x, y, "I", IntegerPixel, grid, &exception);
write("image.png", image);
}
At the very least, I know that this is linked wrong (compiling returns an error inside wand.h that it can't find one of the headers). What's the proper way to go about creating an image from an array within a program using MagickWand for C?
Too much code, it could be summarized with:
image *ConstituteImage(x, y, "I", IntegerPixel, grid, &exception);
write("image.png", image);
But reading the MagickWand link you provided:
MagickWriteImageFile
MagickWriteImageFile() writes an image to an open file descriptor. The
format of the MagickWriteImageFile method is:
MagickBooleanType MagickWriteImageFile ( MagickWand *wand, FILE *file
); A description of each parameter follows:
wand: The magick wand. file: The file descriptor.
So it is clear you have to call:
MagickBooleanType MagickWriteImageFile ( MagickWand *wand, FILE *file );
that header almost definitely tries to include other headers so you need something like:
gcc -I"/Library/Frameworks/libWand.framework/Versions/6.3.0/Headers"
or
gcc -I"/Library/Frameworks/libWand.framework/Versions/6.3.0/Headers/wand"
i'm trying to create a simple Opencv program in C that creates a file capture from a .avi, and it plays it in a window highlighting faces. I'm running a self-compiled version of Opencv (i already tried the same with a jpeg image and it works).
Building goes well, no errors, no warning, but when i launch it this the console output this:
Unknown parameter encountered: "server role"
Ignoring unknown parameter "server role"
And the program simply stops
Previously it was complaining for a missing /home/#user/.smb/smb.conf file, so i tried installing samba ( even though i've still no idea what does samba have to do in all this )
here is my code:
main(){
printf("Ciao!");
cvNamedWindow("window", CV_WINDOW_AUTOSIZE);
cvWaitKey(0);
printf("ok");
CvCapture* capture = cvCreateFileCapture("monsters.avi");
CvHaarClassifierCascade* cascade = load_object_detector("haarcascade_frontalface_alt.xml");
CvMemStorage* storage = cvCreateMemStorage(0);
//List of the faces
CvSeq* faces;
while (0<10) {
CvArr* image = cvQueryFrame(capture);
double scale = 1;
faces = cvHaarDetectObjects(image,cascade, storage, 1.2, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(1,1), cvSize(300,300));
int i;
for(i = 0; i < faces->total; i++ )
{
CvRect face_rect = *(CvRect*)cvGetSeqElem( faces, i );
cvRectangle( image,
cvPoint(face_rect.x*scale,face_rect.y*scale),
cvPoint((face_rect.x+face_rect.width)*scale,(face_rect.y+face_rect.height)*scale),
CV_RGB(255,0,0) , 3, 8, 0);
}
cvReleaseMemStorage( &storage );
cvShowImage("window", image);
}
cvWaitKey(0);
printf("Ciao!");
}
I thank you for your answer, i switched to C++ for my trials. Now i did this:
int main(){
namedWindow("Video", CV_WINDOW_FREERATIO);
VideoCapture cap("sintel.mp4");
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat edges;
for(;;){
Mat frame;
cap>>frame;
cvtColor(frame, edges, CV_BGR2GRAY);
GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
Canny(edges, edges, 0, 30, 3);
imshow("Video", edges);
//cvWaitKey(0);
}
return(0);
}
Now it succesfully load the video and query a frame, evry time i press a key it obviously query another frame and everything works fine, but if i comment the waitkey() the program simply hangs for a bit and crashes if i try to close the window, i'm starting to think there is a problem with codecs or something like that...
There are so many potential problems in the code, most of them related to not coding defensively.
What is cvWaitKey(0); doing after cvNamedWindow()? It's unecessary, remove it!
What happens if the capture was unsucessful? Code defensively:
CvCapture* capture = cvCreateFileCapture("monsters.avi");
if (!capture)
{
// File not found, handle error and possibly quit the application
}
and you should use this technique for every pointer that you receive from OpenCV, ok?
One of the major problems, is that you allocate memory for CvMemStorage before the loop, but inside the loop you release it, which means that after the first loop iteration there will be no longer a valid CvMemStorage* storage, and that's a HUGE problem.
Either move the allocation procedure to the beginning of the loop, so on every iteration memory is allocated/deallocated, or move the cvReleaseMemStorage( &storage ); call out of the loop.
Now it works fine, i changed cvWaitKey() with this
if(waitKey(30) >= 0) break;
I don't understand exactly why but now everything works as it should :)
I’m trying to use OpenCV to write a video file. I have a simple program that loads frames from a video file then accepts to save them
At first the cvCreateVideoWrite always return NULL. I got a answer from your group saying it returns separate images and to try to change the file name to test0001.png, this worked.
But now the cvWriteFrame function always fails, the code is
CString path;
path="d:\\mice\\Test_Day26_2.avi";
CvCapture* capture = cvCaptureFromAVI(path);
IplImage* img = 0;
CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 25; // or 30
int frameW = 640; // 744 for firewire cameras
int frameH = 480; // 480 for firewire cameras
writer=cvCreateVideoWriter("d:\\mice\\test0001.png",CV_FOURCC('P','I','M','1'),
fps,cvSize(frameW,frameH),isColor);
if (writer==0)
MessageBox("could not open writter");
int nFrames = 50;
for(int i=0;i<nFrames;i++){
if (!cvGrabFrame(capture))
MessageBox("could not grab frame");
img=cvRetrieveFrame(capture); // retrieve the captured frame
if (img==0)
MessageBox("could not retrive data");
if (!cvWriteFrame(writer,img) )
MessageBox("could not write frame");
}
cvReleaseVideoWriter(&writer);
Try CV_FOURCC('D', 'I', 'V', 'X'), CV_FOURCC('f', 'f', 'd', 's') (with *.avi filename) or CV_FOURCC_DEFAULT (with *.mpg). Video writing is still quite messy in opencv >_>
I've seen many issues with writing video as well in OpenCV. I found intel iYUV format worked well for what I needed.
Was your library built with HAVE_FFMPEG defined?
If it wasn't,you might need to recompile opencv with that option.You should see something like this in the configure step:
...
Video I/O--------------
Use QuickTime no
Use xine no
Use ffmpeg: yes
Use v4l yes
...
If you don't have ffmpeg,you can get it from here.