opencv - rgb value keeps changing - c++

I'm having some problem with the rgb or in opencv bgr
What I'm trying to do is find the overall value of the bgr of a certain pictures
but every time I run the program without changing anything with exact same pictures the values of the bgr keeps changing..
This is how i coded to find the values of bgr
#include <opencv\cv.h>
#include <opencv\highgui.h>
using namespace std;
char path[255];
int main( int argc, char** argv )
{
IplImage *red[50];
IplImage *green[50];
IplImage *blue[50];
for(int i = 1; i <= 50; i++)
{
IplImage *img;
sprintf(path, "C:\\picture (%01).bmp", i);
img = cvLoadImage(path);
red[i] = cvCreateImage(cvGetSize(img), 8, 1);
green[i] = cvCreateImage(cvGetSize(img), 8, 1);
blue[i] = cvCreateImage(cvGetSize(img), 8, 1);
cvSplit(img, blue[i], green[i], red[i], NULL);
cvReleaseImage(&img);
int total = (int)(blue[i]) + (int)(green[i]) + (int)(red[i]);
cout << total << endl;
cvWaitKey(1);
}
cvWaitKey(0);
return 0;
}

I am not sure how did you achieve type casting from IplImage to int
int total = (int)(blue[i]) + (int)(green[i]) + (int)(red[i]);
but you certainly need to use pixel by pixel summation for each channel (not image by image) to find the overall values.

Try using two loops instead of one, one for loading the images and the other for performing your operation, and let me know if it works..

Related

OpenCV 3 C++ Mat fetching with pointer goes random

I'm quite new to OpenCV and I'm now using version 3.4.1 with C++ implementation. I'm still exploring, so this question is not specific to a project, but is more of a "try to understand how it works". Please consider, with the same idea in mind, that I know that I'm somehow "reinventing the will" with this code, but I wrote this example to understand "HOW IT WORKS".
The idea is:
Read an RGB image
Make it binary
Find Connected areas
Colour each area differently
As an example I'm using a 5x5 pixel RGB image saved as BMP. The image is a white box with black pixels all around it's contour.
Up to the point where I get the ConnectedComponents matrix, named Mat::Labels, it all goes fine. If I print the Matrix I see exactly what I expect:
11111
10001
10001
10001
11111
Remember that I've inverted the threshold so it is correct to get 1 on the edges...
I then create a Mat with same size of Mat::Labels but 3 channels to colour it with RGB. This is named Mat::ColoredLabels.
Next step is to instanciate a pointer that runs through the Mat::Labels and for each position in the Mat::Labels where the value is 1 fill the corresponding Mat:.ColoredLabels position with a color.
HERE THINGS GOT VERY WRONG ! The pointer does not fetch the Mat::Labels row byt row as I would expect but follows some other order.
Questions:
Am I doing something wrong or it is "obvious" that the pointer fetching follows some "umpredictable" order ?
How could I set values of a Matrix (Mat::ColoredLabels) based on the values of another matrix (Mat::Labels) ?
.
#include "opencv2\highgui.hpp"
#include "opencv2\opencv.hpp"
#include <stdio.h>
using namespace cv;
int main(int argc, char *argv[]) {
char* FilePath = "";
Mat Img;
Mat ImgGray;
Mat ImgBinary;
Mat Labels;
uchar *P;
uchar *CP;
// Image acquisition
if (argc < 2) {
printf("Missing argument");
return -1;
}
FilePath = argv[1];
Img = imread(FilePath, CV_LOAD_IMAGE_COLOR);
if (Img.empty()) {
printf("Invalid image");
return -1;
}
// Convert to Gray...I know I could convert it right away while loading....
cvtColor(Img, ImgGray, CV_RGB2GRAY);
// Threshold (inverted) to obtain black background and white blobs-> it works
threshold(ImgGray, ImgBinary, 170, 255, CV_THRESH_BINARY_INV);
// Find Connected Components and put the 1/0 result in Mat::Labels
int BlobsNum = connectedComponents(ImgBinary, Labels, 8, CV_16U);
// Just to see what comes out with a 5x5 image. I get:
// 11111
// 10001
// 10001
// 10001
// 11111
std::cout << Labels << "\n";
// Prepare to fetch the Mat(s) with pointer to be fast
int nRows = Labels.rows;
int nCols = Labels.cols * Labels.channels();
if (Labels.isContinuous()) {
nCols *= nRows;
nRows = 1;
}
// Prepare a Mat as big as LAbels but with 3 channels to color different blobs
Mat ColoredLabels(Img.rows, Img.cols, CV_8UC3, cv::Scalar(127, 127, 127));
int ColoredLabelsNumChannels = ColoredLabels.channels();
// Fetch Mat::Labels and Mat::ColoredLabes with the same for cycle...
for (int i = 0; i < nRows; i++) {
// !!! HERE SOMETHING GOES WRONG !!!!
P = Labels.ptr<uchar>(i);
CP = ColoredLabels.ptr<uchar>(i);
for (int j = 0; j < nCols; j++) {
// The coloring operation does not work
if (P[j] > 0) {
CP[j*ColoredLabelsNumChannels] = 0;
CP[j*ColoredLabelsNumChannels + 1] = 0;
CP[j*ColoredLabelsNumChannels + 2] = 255;
}
}
}
std::cout << "\n" << ColoredLabels << "\n";
namedWindow("ColoredLabels", CV_WINDOW_NORMAL);
imshow("ColoredLabels", ColoredLabels);
waitKey(0);
printf("Execution completed succesfully");
return 0;
}
You used connectedComponents function with CV_16U parameter. This means that the single element of the image will consist of 16 bits (hence '16') and you have to interpret them as unsigned integer (hence 'U'). And since ptr returns a pointer, you have to dereference it to get the value.
Therefore you should access label image elements in the following way:
unsigned short val = *Labels.ptr<unsigned short>(i) // or uint16_t
unsigned short val = Labels.at<unsigned short>.at(y, x);
Regarding your second question, it is as simple as that, but of course you have to understand which type casts result in loss of precisions or overflows and which ones not.
mat0.at<int>(y, x) = mat1.at<int>(y, x); // both matrices have CV_32S types
mat2.at<int>(y, x) = mat3.at<char>(y,x); // CV_32S and CV_8S
// Implicit cast occurs. Possible information loss: assigning 32-bit integer values to 8-bit ints
// mat4.at<unsigned char>(y, x) = mat5.at<unsigned int>(y, x); // CV_8U and CV_32U

How to prepare image data for kmeans opencv function input? [duplicate]

I am making a function using C++ and OpenCV that will detect the color of a pixel in an image, determine what color range it is in, and replace it with a generic color. For example, green could range from dark green to light green, the program would determine that its still green and replace it with a simple green, making the output image very simple looking. everything is set up but I'm having trouble defining the characteristics of each range and was curious if anyone knows or a formula that, given BGR values, could determine the overall color of a pixel. If not I'll have to do much experimentation and make it myself, but if something already exists that'd save time. I've done plenty of research and haven't found anything so far.
If you want to make your image simpler (i.e. with less colors), but good looking, you have a few options:
A simple approach would be to divide (integer division) by a factor N the image, and then multiply by a factor N.
Or you can divide your image into K colors, using some clustering algorithm such as kmeans showed here, or median-cut algorithm.
Original image:
Reduced colors (quantized, N = 64):
Reduced colors (clustered, K = 8):
Code Quantization:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
imshow("Original", img);
uchar N = 64;
img /= N;
img *= N;
imshow("Reduced", img);
waitKey();
return 0;
}
Code kmeans:
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
imshow("Original", img);
// Cluster
int K = 8;
int n = img.rows * img.cols;
Mat data = img.reshape(1, n);
data.convertTo(data, CV_32F);
vector<int> labels;
Mat1f colors;
kmeans(data, K, labels, cv::TermCriteria(), 1, cv::KMEANS_PP_CENTERS, colors);
for (int i = 0; i < n; ++i)
{
data.at<float>(i, 0) = colors(labels[i], 0);
data.at<float>(i, 1) = colors(labels[i], 1);
data.at<float>(i, 2) = colors(labels[i], 2);
}
Mat reduced = data.reshape(3, img.rows);
reduced.convertTo(reduced, CV_8U);
imshow("Reduced", reduced);
waitKey();
return 0;
}
Yes, what you probably mean by "Overall color of a pixel" is either the "Hue" or "Saturation" of the color.
So you want a formula that transform RGB to HSV (Hue, Saturation, Value), and then you would only be interested by the Hue or Saturation values.
See: Algorithm to convert RGB to HSV and HSV to RGB in range 0-255 for both
EDIT: You might need to max out the saturation, and then convert it back to RGB, and inspect which value is the highest (for instance (255,0,0), or (255,0,255), etc.
If you want to access RGB value of all pixels , then below is code,
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat image = imread("image_path");
for(int row = 1; row < image.rows; row++)
{
for(int col = 1; col < image.cols; col++)
{
Vec3b rgb = image.at<Vec3b>(row, col);
}
}
}

Why Png Compression doesn't change destination size (C++)? OpenCV VS2010

I have tested this code with various values from compression_params.push_back(1); to compression_params.push_back(9); but the PNG image always has same size. 1950x1080 (contains screenshot of Google map - not the satellite photo) has 2,36 MB (2 477 230 bytes. Is this normal is takes so much. I thought png images are small size if they do not contain photos.
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
compression_params.push_back(1);
try {
imwrite("RGB_1.png", source, compression_params);
}
catch (runtime_error& ex) {
fprintf(stderr, "Exception converting image to PNG format: %s\n", ex.what());
return 1;
}
Why is it? Also I cannot find out how to create the PNG object in memory (to keep the encode data in buffer). This means, I would like to save more images into one file (e.g database) so I need to convert into buffer and then save add buffer to file. Is it possible to do it usin OpenCV? Your tips welcome.
I think PNG should support some feature where the algorithm auto-selects background color, so if you see some cv::Scallar(200,200,200) takes too many place on the image, the algorithm could set it as background color and it is removed from the image so the image should take small place. So when it takes same size as regular PNG or even more, that doesn't give any sense.
i am not an expert on this subject but tried to test some compression_params maybe you will find the answer by testing the code below.
probably adding the following lines will do the trick.
compression_params.push_back(IMWRITE_PNG_STRATEGY);
compression_params.push_back(IMWRITE_PNG_STRATEGY_DEFAULT);
or you can try other alternatives accordind to documentation
also i opened an issue
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
void createAlphaMat(Mat &mat)
{
CV_Assert(mat.channels() == 4);
for (int i = 0; i < mat.rows; ++i) {
for (int j = 0; j < mat.cols; ++j) {
Vec4b& bgra = mat.at<Vec4b>(i, j);
bgra[0] = UCHAR_MAX; // Blue
bgra[1] = saturate_cast<uchar>((float(mat.cols - j)) / ((float)mat.cols) * UCHAR_MAX); // Green
bgra[2] = saturate_cast<uchar>((float(mat.rows - i)) / ((float)mat.rows) * UCHAR_MAX); // Red
bgra[3] = saturate_cast<uchar>(0.5 * (bgra[1] + bgra[2])); // Alpha
}
}
}
int main( int argc, char** argv )
{
// Create mat with alpha channel
Mat mat(480, 640, CV_8UC4);
createAlphaMat(mat);
vector<int> compression_params;
compression_params.push_back(IMWRITE_PNG_COMPRESSION);
compression_params.push_back(0);
compression_params.push_back(IMWRITE_PNG_STRATEGY);
compression_params.push_back(IMWRITE_PNG_STRATEGY_DEFAULT);
for (int i = 0; i < 10; i++)
{
compression_params[1] = i;
imwrite(format("alpha%d.png",i), mat, compression_params);
}
return 0;
}

How to make all images of same size and write them in a folder

I am trying to convert different sizes of images from my different folders to the same size as defined in the width and height and them save them in different folder or replace them, I use the function cv::resize for it, and surely imwrite may be use for saving them, but its not working for me, as it showing me error in the parameters of resize.
int count = 0;
int width = 144;
int height = 33;
vector<string>::const_iterator i;
string Dir;
for (i = all_names.begin(); i != all_names.end(); ++i)
{
Dir=( (count < files.size() ) ? YourImagesDirectory_2 : YourImagesDirectory_3);
Mat row_img = cv::imread( Dir +*i, 0 );
cv::resize(row_img , width , height);
imwrite( "D:\\TestData\\img_resize.jpg", img_resize );
++count;
}
After resize this function :
imwrite( "D:\\TestData\\img_resize.jpg", img_resize );
Only save one image to my folder test , i want all of them in my folder
Here is an example for how to resize an image:
Mat img = imread("C:\\foo.bmp");
Mat img_resize;
resize(img, img_resize, Size(144, 33));
EDIT:
Supposed that you have several images named as image001.jpg, image002.jpg, image003.jpg, image004.jpg, image005.jpg..., and want to save them after resizing. Hopes the following code works it out.
#include <cv.h>
#include <highgui.h>
using namespace cv;
char pathLoading[255];
char pathSaving[255];
char num[10];
char jpg[10] = ".jpg";
int counter = 1;
int main(int argc, char** argv) {
while (1) {
if (counter < 6) {
// To load 5 images
strcpy(pathLoading, "c:\\image");
sprintf(num, "%03i", counter);
strcat(pathLoading, num);
strcat(pathLoading, jpg);
Mat image = imread(pathLoading);
Mat image_resize;
resize(image, image_resize, Size(144, 33));
// To save 5 images
strcpy(pathSaving, "c:\\image_resize");
sprintf(num, "%03i", counter);
strcat(pathSaving, num);
strcat(pathSaving, jpg);
imwrite(pathSaving, image_resize);
counter++;
}
}
return 0;
}
Here is the way through which i can csave multiple images in the folder :
for (i = all_names.begin() ; i!= all_names.end() ; i++)
{
Dir=( (count < files.size() ) ? YourImagesDirectory : YourImagesDirectory_2);
Mat row_img = cv::imread(Dir+*i );
//imshow ("show",row_img);
Mat img_resize;
resize(row_img, img_resize, Size(144, 33));
Mat img = img_resize;
sprintf(buffer,"D:\\image%u.jpg",count);
imwrite(buffer,img);
//imwrite("D:\\TestData\\*.jpg" , img_resize);
count++;
}
Use the functions :
sprintf(buffer,"D:\\image%u.jpg",count);
imwrite(buffer,img);
For giving directory , name and imwrite for saving there
If the only goal is to resize the images I would guess it would be simpler to use dedicated software with batch processing capability, e.g. IrfanView.
If this is programming exercise, nevermind my answer and look at answers by other people.
HINT: You are saving all your images with single filename, thus effectively rewriting the previously converted images with the new ones.

Knowing a pixel value after making an RGBtoHSV conversion OpenCv

Im trying to get the H,S and V Values of an image, so i convert an RGB image to HSV, and then just ask for the desired values, and then print them.. Im not quite sure im making this right, because when printing the Value (V of hsV) i get values of 100+ and i understand that the V just goes to 0-100, maybe im not using a correct method, here's the code:
#include "opencv/highgui.h"
#include "opencv/cv.h"
#include <cstdlib>
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char** argv) {
int i=0,total=0;
IplImage* img = cvLoadImage( argv[1] );
IplImage* hsv;
CvSize size;
int key = 0, depth;
size = cvGetSize(img);
depth = img->depth;
hsv = cvCreateImage(size, depth, 3);
cvCvtColor( img, hsv, CV_BGR2HSV );
for(i=0;i<480;i++){ //asking for the values in \ form (1,1)(2,2),...(480,480)
CvScalar s;
s = cvGet2D(hsv,i,i);
printf("s=%f\n,s.val[2]); //s.val[2] equals to hs**V** right?
}
cvReleaseImage(&img);
cvReleaseImage(&val);
return 0;
}
The other answer here is correct but here is a code snippet that I have to calculate the V channel in opencv. I get the value from the Gimp app and this function gives me the opencv value.
//Max values: App HSV H=360 S=100 V=100 OpenCV H=180 S=255 V=255
double newHSV(double value)
{
//new_val = value * opencv_max_range / other_app_max_range
double newValue = value * 255 / 100;
return newValue;
}
To check your opencv HSV values in another application like Gimp, just calculate the formula to:
gimp_value = opencv_value * other_app_max_range / opencv_max_range
The way you're doing it is correct. Just that values are a little different.
H should ideally go from 0-360. But because a byte can only hold 0-255, H values are halved. So the range is 0-180.
V and S use the full range of 0-255 to specify value and saturation.
You can read more about it here: http://opencv.willowgarage.com/documentation/python/miscellaneous_image_transformations.html#cvtcolor