In OpenCV, what's the difference between CV_8U and CV_8UC1? - opencv

In OpenCV, is there a difference between CV_8U and CV_8UC1? Do they both refer to an 8-bit unsigned type with one channel? If so, why are there two names? If not, what's the difference?

You can see from this answer, they evaluate to identical types.
As for why there are two names, if you look at how the #defines are structured (again, see linked answer), a type in OpenCV has 2 parts, the depth, and the number of channels. The system is flexible enough to let you define new types with up to 512 channels. It just so happens that when you specify 1 channel, the channel component of type is set to 0 which makes the result equivalent to simply using the depth CV_8U.

They should be the same. For me, I prefer to use CV_8UC1 since it makes my code more clear that how many number of channels I am working with.
However, if you are dealing with a matrix that has 10 channels or more, you need to specify the number of channels.
You may want to experiment with the number of channels using the code snippet below.
#define CV_MAT_ELEM_CN( mat, elemtype, row, col ) \
(*(elemtype*)((mat).data.ptr + (size_t)(mat).step*(row) + sizeof(elemtype)*(col)))
...
CvMat *M = cvCreateMat(4, 4, CV_32FC(10));
for(int ch = 0; ch < 10; ch++) {
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
CV_MAT_ELEM_CN(*M, float, i, j * CV_MAT_CN(M->type) + ch) = 0.0;
cout << CV_MAT_ELEM_CN(*M, float, i, j * CV_MAT_CN(M->type) + ch) << " ";
}
}
cout << endl << endl;
}
cvReleaseMat(&M);
credit: http://note.sonots.com/OpenCV/MatrixOperations.html

Related

How to implement Sobel operator

I have implemented Sobel operator in vertical direction. But the result which I am getting is very poor. I have attached my code below.
int mask_size= 3;
char mask [3][3]= {{-1,0,1},{-2,0,2},{-1,0,1}};
void sobel(Mat input_image)
{
/**Padding m-1 and n-1 zeroes to the result where m and n are mask_size**/
Mat result=Mat::zeros(input_image.rows+(mask_size - 1) * 2,input_image.cols+(mask_size - 1) * 2,CV_8UC1);
Mat result1=Mat::zeros(result.rows,result.cols,CV_8UC1);
int sum= 0;
/*For loop for copying original values to new padded image **/
for(int i=0;i<input_image.rows;i++)
for(int j=0;j<input_image.cols;j++)
result.at<uchar>(i+(mask_size-1),j+(mask_size-1))=input_image.at<uchar>(i,j);
GaussianBlur( result, result, Size(5,5), 0, 0, BORDER_DEFAULT );
/**For loop to implement the convolution **/
for(int i=0;i<result.rows-(mask_size - 1);i++)
for(int j=0;j<result.cols-(mask_size - 1);j++)
{
int counter=0;
int counterX=0,counterY=0;
sum= 0;
for(int k= i ; k < i + mask_size ; k++)
{
for(int l= j ; l< j + mask_size ; l++)
{
sum+=result.at<uchar>(k,l) * mask[counterX][counterY];
counterY++;
}
counterY=0;
counterX++;
}
result1.at<uchar>(i+mask_size/2,j+mask_size/2)=sum/(mask_size * mask_size);
}
/** Truncating all the extras rows and columns **/
result=Mat::zeros( result1.rows - (mask_size - 1) * 2, result1.cols - (mask_size - 1) * 2,CV_8UC1);
for(int i=0;i<result.rows;i++)
for(int j=0;j<result.cols;j++)
result.at<uchar>(i,j)=result1.at<uchar>(i+(mask_size - 1),j+(mask_size - 1));
imshow("Input",result);
imwrite("output2.tif",result);
}
My input to the algorithm is
My output is
I have also tried using Gaussian blur before actually convolving an image and the output I got is
The output which I am expecting is
The guide I am using is: https://www.tutorialspoint.com/dip/sobel_operator.htm
Your convolution looks ok although I only had a quick look.
Check your output type. It's unsigned char.
Now think about the values your output pixels may have if you have negative kernel values and if it is a good idea to store them in uchar directly.
If you store -1 in an unsigned char it will be wrapped around and your output is 255. In case you're wondering where all that excess white stuff is coming from. That's actually small negative gradients.
The desired result looks like the absolute of the Sobel output values.

partition a set of images into k clusters with opencv

I have an image data set that I would like to partition into k clusters. I am trying to use the opencv implementation of k-means clustering.
Firstly, I store my Mat images into a vector of Mat and then I am trying to use the kmeans function. However, I am getting an assertion error.
Should the images be stored into a different kind of structure? I have read the k-means documentation and I dont seem to understand what I am doing wrong. This is my code:
Thank you in advance,
vector <Mat> images;
string folder = "D:\\football\\positive_clustering\\";
string mask = "*.bmp";
vector<string> files = getFileList(folder + mask);
for (int i = 0; i < files.size(); i++)
{
Mat img = imread(folder + files[i]);
images.push_back(img);
}
cout << "Vector of positive samples created" << endl;
int k = 10;
cv::Mat bestLabels;
cv::kmeans(images, k, bestLabels, TermCriteria(), 3, KMEANS_PP_CENTERS);
//have a look
vector<cv::Mat> clusterViz(bestLabels.rows);
for (int i = 0; i<bestLabels.rows; i++)
{
clusterViz[bestLabels.at<int>(i)].push_back(cv::Mat(images[bestLabels.at<int>(i)]));
}
namedWindow("clusters", WINDOW_NORMAL);
for (int i = 0; i<clusterViz.size(); i++)
{
cv::imshow("clusters", clusterViz[i]);
cv::waitKey();
}

Preserve Color-Depth of imported Images

When importing Images with the
loadImage("...")
Command, iterating over the pixels in like this:
img.loadPixels();
int w = img.width;
int h = img.height;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int loc = x + y*w;
float r = red(img.pixels[loc]);
float g = green(img.pixels[loc]);
float b = blue(img.pixels[loc]);
println(r + ", " + g + ", " + b);
}
}
The R G B Values always seem to be between 0 and 255 even if the image file has a depth of 16 bit per channel, where the values should be between 0 and 65535.
Is it possible to preserve the correct color depth?
You haven't said which library the loadImage command is from.
There might be a 16-bit version, but it's unlikely. 24 bits is a sort of standard, suitable for all but very high end work.
What I suggest you do is take a look at my TIFF loader (which, like loadImage, returns 24 bit images), and modify it to return 16-bit channels. It's not difficult, just a case of not discarding the lower bits of the larger channel images (float and 16 bit).
Her'e the TIFF loader:
https://github.com/MalcolmMcLean/tiffloader

c++ vector push_back inconsistent behavior

I push back two sets(A={A1,A2,A3},B={B1,B2,B3}) of equal matrices(A1=B1,A2=B2,A3=B3) of same type(CV_32FC) in two different vectors(Va and Vb) of same type. When i compare the contents of the vectors pair by pair(Va[0] vs Vb[0], Va[1] vs Vb[1],Va[2] vs Vb[2])they are different. How is this possible?
Code explanation:
A= imgs_lab_channels.
Lab_channel_current_FG = Foreground image
Lab_channel_current_BG = Background image
Lab_channel_current=Lab_channel_current_FG+Lab_channel_current_BG
push Lab channel_current into vector Lab_channels
So B=Lab_channels
I check that
Lab_channel_current= imgs_lab_channels[i].
When I read back the matrices from the vectors A and B they are different.
Code snippet:
std::vector<cv::Mat> imgs_lab_channels;
split(imgs_lab, imgs_lab_channels);
std::vector<cv::Mat> Lab_channels;
cv::Mat Lab_channel_current_FG;
cv::Mat Lab_channel_current_BG;
cv::Mat Lab_channel_current;
for(int i = 0; i < 3; i++)
{
// FG_mask and BG_mask are 0-1 binary matrices of type 32FC1
// and with same size as imgs_lab_channels. FG_mask and BG_mask
// select the Foreground and background respectively. Omitted for
// sake of clarity
Lab_channel_current_FG=imgs_lab_channels[i].mul(FG_mask);
Lab_channel_current_BG=imgs_lab_channels[i].mul(BG_mask);
// add the FG and the BG image
Lab_channel_current=Lab_channel_current_FG+Lab_channel_current_BG;
Lab_channels.push_back(Lab_channel_current);
}
for(int j=0;j<3;j++)
{
temp2 = Lab_channels[j]-imgs_lab_channels[j];
double min2, max2;
cv::minMaxLoc(temp2, &min2, &max2);
std::cout << "temp2 min,max="<< min2 << "," << max2 << std::endl;
}

How does #pragma simd reduction(<operator>:<variable>) work under the hood?

I would like to know in more detail how the simd reduction clause used by Intel compilers works under the hood.
In particular, for a loop of the form
double x = x_initial;
#pragma simd reduction(<operator1>:x)
for( int i = 0; i < N; i++ )
x <operator2> some_value;
my naive guess is as follows:
The compiler initializes a private copy of x for each vector lane, then iterates through the loop one vector width at a time. If the vector width is 4 doubles, for example, this would correspond to N/4 iterations plus a peel loop at the end. At each step of the iteration, each lane's private copy of x is updated using operator2, then at the end, the 4 vector lanes' private copies are combined using operator1. The auto-vectorization guide does not appear to address this directly.
I did some experimentation and found some results that agree with my expectation and some that don't. For example, I tried the case
double x = 1;
#pragma simd reduction(*:x) assert
for( int i = 0; i < 16; i++ )
x += a[i]; // All elements of a are equal to 3.0
cout << "x after (*:x), x += a[i] loop: " << x << endl;
where operator1 is * and operator2 is +=. When I compile for avx2, which has a vector width of 4 doubles, the output is 28561 = ( 1 + 4*a[i] )^4. This implies that the code first initializes 4 lane-private copies of x to 1, then adds 3 to each of those copies 4 times as the 4-double-wide vector lane iterates across the trip count of 16. Each lane-private copy of x is now equal to 13. Finally, the lane-private copies are combined (reduced) using operator2 which is *, yielding 13*13*13*13 = 28561.
However, when I switch the * and + operators, like so
x = 1;
#pragma simd reduction(+:x) assert
for( int i = 0; i < 16; i++ )
x *= a[i];
cout << "x after (+:x), x *= a[i] loop: " << x << endl;
and compile again for avx2, the output is 1.0. If my theory were correct, each vector lane should end up containing a value of 1*3^4, which would then be combined using + to yield 4*3^4 = 324. Evidently this is not the case. What am I missing?

Resources