OpenCV reading RGB Values. Values are not consistent for every run - c++

When running this code with the same image and mask I occasionally get values that differ previously. For example
Normal/Expected Results
Abnormal Results
As can be seen in the two results I somehow receive negative RGB values. The Abnormal Results show up around every 5-8 runs for the exact same image with the exact same mask.
What do I need to change to prevent the occasional abnormal result?
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string>
using namespace cv;
using namespace std;
float get_color(Mat img,Mat &mask){
Mat img1 = img;
Mat hist;
int dims = 1;
int histSize = 255;
float hranges[] = { 0, 255 };
const float *ranges = {hranges};
calcHist(&img1,1,0,mask,hist, dims, &histSize, &ranges ,true ,false);
int sum=0;
for(int i = 0;i<256;i++){
sum += hist.at<float>(i,0);
}
Mat weights = hist/sum;
float hist_avg=0.0;
for(int i = 0;i<256;i++){
hist_avg += i*weights.at<float>(i,0);
}
return hist_avg;
}
int main(int argc, char** argv){
Mat aa = imread("/Users/dnguyen/Desktop/snapshot207042/pic.jpg", CV_LOAD_IMAGE_COLOR);
vector<Mat> bgr;
split(aa, bgr);
Mat b = bgr[0];
Mat g = bgr[1];
Mat r = bgr[2];
for(unsigned int i=1;i<23;i++){
stringstream ss;
ss << i;
string str = ss.str();
string file_name = "/Users/dnguyen/Desktop/okay/data/card_masks/"+str+"_mask.png";
Mat mask = imread(file_name,0);
Mat cc;
threshold(mask,cc,90,255,THRESH_BINARY);
float b_avg = get_color(b, cc);
float g_avg = get_color(g, cc);
float r_avg = get_color(r, cc);
cout << b_avg << ","<< g_avg << "," << r_avg << endl;
}
}

Related

OpenCV C++ - Video saved using VideoWritter cannot be opened

So I am trying to edit all the frames from input video and than save them to the output. The saved video appears and has the proper filesize but can't open and the imshow inside the while doesn't show the frames at all (only a blank window). I've tried numerous codecs (H264,MJPG,MPEG,MPV4,XVID,CVID) and non of them make it work. What could be the problem? Also, the first function is for converting RGB to YUV and returning the gray channel, while the second one works with HPF and LPF. These functions work on individual images so I don't think they are the problem.
#include <opencv2\opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat KonverzijaRGB2YUV(Mat ulazniFrejm){
int width = ulazniFrejm.cols;
int height = ulazniFrejm.rows;
Mat konvertovan(height, width, CV_8UC3, Scalar(0,0,0));
for(int i=0; i<width; i++){
for(int j=0; j<height; j++){
double R = ulazniFrejm.at<Vec3b>(j,i).val[0];
double G = ulazniFrejm.at<Vec3b>(j,i).val[1];
double B = ulazniFrejm.at<Vec3b>(j,i).val[2];
double Y = 0.299*R + 0.587*G + 0.114*B;
double U = 0.436*(B-Y) / (1-0.114);
double V = 0.615*(R-Y) / (1-0.299);
konvertovan.at<Vec3b>(j,i).val[0] = Y;
konvertovan.at<Vec3b>(j,i).val[1] = U;
konvertovan.at<Vec3b>(j,i).val[2] = V;
}
}
Mat Ykanal[3];
split (konvertovan, Ykanal);
Mat YkanalRGB;
cvtColor(Ykanal[0], YkanalRGB, CV_GRAY2RGB);
return YkanalRGB;
}
Mat Izostravanje(Mat ulazniFrejm){
Mat izostrena;
float valLaplas[] =
{ 0.,-1.,0.,
-1.,4.,-1.,
0.,-1.,0. };
Mat kernelLaplas(Size(3,3), CV_32FC1, valLaplas);
Mat Laplas;
filter2D(ulazniFrejm, Laplas, -1, kernelLaplas);
convertScaleAbs(Laplas, Laplas);
Mat Gaus;
GaussianBlur(ulazniFrejm, Gaus, Size(3,3), 0, 0);
addWeighted(Laplas, 1.4, Gaus, 1.0, 0, izostrena);
return izostrena;
}
int main(int argc, char** argv){
VideoCapture ulazniVideo("esmeralda.mp4");
int brojFrejmova = static_cast<int>(ulazniVideo.get(CV_CAP_PROP_FRAME_COUNT));
if(!ulazniVideo.isOpened()){
cout << "Video se ne moze otvoriti" << endl;
}
waitKey(1000);
Size frameSize = Size((int)ulazniVideo.get(CV_CAP_PROP_FRAME_WIDTH), (int)ulazniVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
int fps = ulazniVideo.get(CV_CAP_PROP_FPS);
int ex = -1;
VideoWriter izlazniVideo;
izlazniVideo.open("esmeralda.mp4", ex, fps, frameSize, true);
int brojac = 0;
while(true){
Mat frame;
ulazniVideo >> frame;
Mat konvertovanFrejm;
konvertovanFrejm = KonverzijaRGB2YUV(frame);
Mat izostrenFrejm;
izostrenFrejm = Izostravanje(konvertovanFrejm);
if(frame.empty()){
break;
}
izlazniVideo << frame;
brojac++;
namedWindow("Video", CV_WINDOW_AUTOSIZE);
imshow("Video", izostrenFrejm);
int waitKey(1000/fps);
}
waitKey(0);
return 0;
}

C++ OpenCV downsized videoCapture frame stretched and cropped

I am trying to get a calibration program for captured thermal video converted from python to C++, and the first step in the process is binning the pixels in the image down from 480x640 to 240x320, so pixel bins of 2x2. The returned image after binning (using the same logic from the correctly functioning python version) the image being returned is the left half of the image stretched across the width of the image, rather than giving the whole image only at the smaller resolution.
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/videoio/videoio.hpp>
#include <opencv2/video.hpp>
#include <opencv2/imgcodecs.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat binImg(Mat);
int asInt(uint8_t);
uint8_t as8bit(int);
Mat rotate(Mat, double);
int main(int argc, char *argv[]){
VideoCapture cap(argv[1]);
int frameCount = cap.get(cv::CAP_PROP_FRAME_COUNT);
int frameWidth = cap.get(cv::CAP_PROP_FRAME_WIDTH);
int frameHeight = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
Mat buf [frameCount]; //create new array of Mat for the calibrated video
int fc = 0;
VideoWriter video("cppThermalTest.avi",CV_FOURCC('X','V','I','D'), 15, Size(240, 320), false); //create empty video #15fps, 320x240, isColor=false
while (fc < frameCount){
Mat frame(640, 480, CV_8UC1, Scalar(70));
cap >> frame;
Mat temp = binImg(frame);//bin the frame
imshow("test", temp);
imwrite("test.jpg", temp);
waitKey(0);
video.write(temp); //write the binned frame to the video
cout << fc << endl;
fc++;
}
cap.release();
video.release();
return 0;
}
Mat binImg(Mat frame){
int frameWidth = frame.cols / 2; //480 / 2
int frameHeight = frame.rows / 2; //640 / 2
cout << frameHeight << " " << frameWidth << endl;
Mat binFrame(frameHeight, frameWidth, CV_8UC1);
for(int i=0; i<binFrame.rows; i++){
for(int j=0; j<binFrame.cols; j++){
int ul = asInt(frame.at<uint8_t>((2*i),(2*j)));
int bl = asInt(frame.at<uint8_t>(((2*i)+1),(2*j)));
int ur = asInt(frame.at<uint8_t>((2*i), ((2*j)+1)));
int br = asInt(frame.at<uint8_t>(((2*i)+1),((2*j)+1)));
int avg = (ul + ur + bl + br) / 4;
binFrame.at<uint8_t>(i,j) = as8bit(avg); //set the matrix element to the new value
}
}
return binFrame;
}
int asInt(uint8_t val){
//convert unsigned 8 bit int to int
int temp = val;
return temp;
}
uint8_t as8bit(int val){
//convert int to unsigned 8 bit int
uint8_t temp = val;
return temp;
}
Mat rotate(Mat src, double angle){ //rotate function returning mat object with parametres imagefile and angle
Mat dst; //Mat object for output image file
Point2f pt(src.cols/2., src.rows/2.); //point from where to rotate
Mat r = getRotationMatrix2D(pt, angle, 1.0); //Mat object for storing after rotation
warpAffine(src, dst, r, Size(src.cols, src.rows)); ///applie an affine transforation to image.
return dst; //returning Mat object for output image file
}
After playing around with things for a while, I found that when doing "at" calls, specifying 0 as a third parameter (e.g. binFrame.at<uint8_t>(i,j, 0) = as8bit(avg);) fixes the issue.

Take the color avarage of each column of a picture using OpenCV with C++ on Visual Studio 2019

I'm new using C++ and a need to compute the average of the red color in each column. Subsequently, I need to make a graph of the color density level per column.
This is the picture that i using, is a sample of a bone densitomery:
This is my code so far:
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <windows.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
FARPROC pGetPixel;
std::cout << "Medidas de muestra 1: \n";
Mat img = imread("C:\\Users\\Jimena G. Gordillo\\OneDrive\\Pictures\\den.bmp");
int matriz = img.cols * img.rows * 3;
const size_t chanels = 3; //RGB
//Lectura de cada pixel
for (int x = 0; x < img.cols; x++) {
for (int y = 0; y < img.rows; y++) {
size_t p = y * img.cols * chanels + x * chanels; //
uchar b = img.data[p + 0];
uchar g = img.data[p + 1];
uchar r = img.data[p + 2];
for (int i = 0; i <= img.cols; i++) { //here is where I want to obtain the sum of each column
int sum = sum + i;
//Calculate average
long long average = sum / img.rows; // average is divided by the total of rows
}
}
}
cout << "Filas: " << img.rows<< endl;
cout << "Columnas: " << img.cols << endl;
cout << "Area: " << matriz << endl;
namedWindow("imagen", WINDOW_AUTOSIZE);
imshow("imagen", img);
waitKey();
return 0;
}
Any help is appreciated.
You are trying to check row by row not column by column also the third for loop is not needed.
Here is the solution for each channel(red,green,blue) columns average and graph of the column averages for each channel.
Source:
Red Channel Graph for each column average:
Green Channel Graph for each column average:
Blue Channel Graph for each column average:
Code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("/ur/source/image/directory/img.png");
imshow("Source",img);
long int avgRedChannel = 0,avgGreenChannel = 0, avgBlueChannel = 0;
Mat graphRedChannel = Mat::zeros(Size(img.cols,300),CV_8UC1);
Mat graphGreenChannel = Mat::zeros(Size(img.cols,300),CV_8UC1);
Mat graphBlueChannel = Mat::zeros(Size(img.cols,300),CV_8UC1);
for(int i=0;i<img.cols;i++)
{
for(int j=0;j<img.rows;j++)
{
avgBlueChannel += (int)img.at<Vec3b>(Point(i,j))[0];
avgGreenChannel += (int)img.at<Vec3b>(Point(i,j))[1];
avgRedChannel += (int)img.at<Vec3b>(Point(i,j))[2];
}
graphBlueChannel.at<uchar>(Point(i,(avgBlueChannel/img.rows))) = 255;
graphGreenChannel.at<uchar>(Point(i,(avgGreenChannel/img.rows))) = 255;
graphRedChannel.at<uchar>(Point(i,(avgRedChannel/img.rows))) = 255;
avgBlueChannel = 0;
avgGreenChannel = 0;
avgRedChannel = 0;
}
imshow("RedChannelGraph",graphRedChannel);
imshow("GreenChannelGraph",graphGreenChannel);
imshow("BlueChannelGraph",graphBlueChannel);
waitKey(0);
return(0);
}

Downsampling an image by 2, OpenCV

guys. Just for you know, I'm new to this environment, so if I do something wrong, feel free to warn me.
So, I was trying to create a basic algorithm for downsampling an image by an ancient technique. I'm new to OpenCV as well.
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
#include <iostream>
using namespace std;
using namespace cv;
void filter2(const Mat &image, Mat &out)
{
// convert and split
Mat imgf;
image.convertTo(imgf, CV_32F, 1.0 / 255.0);
Mat chn[3];
split(imgf, chn);
Mat newchn[3];
// Resampling by 2
for (int dim = 0; dim < 3; dim++) {
Mat dummy2;
Mat dummy = chn[dim];
for (int i = 0; i < chn[dim].rows/2; i++) {
for (int j = 0; j < chn[dim].cols/2; j++) {
dummy2.at<double>(i,j) = dummy.at<double>(i*2,j*2);
}
}
dummy2 = newchn[dim];
}
// merge and convert
merge(newchn, 3, imgf);
imgf.convertTo(out, CV_8U, 255.0);
}
int main(int agra, char** argv) {
String fn = "eva_green.png";
if (agra > 1) fn = argv[1];
Mat image = imread(fn);
if (image.empty())
{
cerr << "No image";
return 1;
}
Mat result;
filter2(image, result);
imshow("org", image);
imshow("res", result);
waitKey(0);
return 0;
}
The "filter2" function does the job. What is wrong with my code?

Contrast & brightness of images using IplImage

Please have a look at the following code
using namespace cv;
double alpha = 1.6;
int beta = 50;
int i = 0;
IplImage* input_img = cvLoadImage("c:\\Moori.jpg", CV_LOAD_IMAGE_GRAYSCALE);
IplImage* imageGray = cvCreateImage(cvSize(input_img->width, input_img->height), IPL_DEPTH_8U, 1);
for( int y = 0; y < input_img->height; y++ )
{
for( int x = 0; x < input_img->width; x++ )
{
i = y * imageGray->width + x;
imageGray->imageData[i] = (alpha * input_img->imageData[i]) + beta;
}
}
cvNamedWindow("Image IplImage", 1);
cvShowImage("Image IplImage", imageGray);
waitKey();
cvReleaseImage(&imageGray);
cvReleaseImage(&input_img);
cvDestroyWindow("Image IplImage");
when I run this code, it shows an image with many dark pixels.
But, when i run the code, which is available at:
http://docs.opencv.org/doc/tutorials/core/basic_linear_transform/basic_linear_transform.html
it works fine. I want to do by IplImage. Please help
saturate_cast is for c++.
http://docs.opencv.org/modules/core/doc/intro.html
Finally, I have solved this problem.
IplImage* img;
cvNamedWindow("Display");
while(true)
{
img = cvLoadImage("Moori.jpg");
CvScalar brVal = cvScalarAll(abs(10.0));
cvAddS(img, brVal, img, NULL);
IplImage *pTempImg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, img->nChannels);
cvSet( pTempImg, cvScalarAll(1), NULL );
double scale = 1.5;
cvMul(img, pTempImg, img, scale);
cvReleaseImage(&pTempImg);
cvShowImage("Display", img);
cvReleaseImage(&img);
int c=cvWaitKey(10);
if(c==27) break;
}
cvDestroyWindow("Display");
You dont have to cast the image values to uchar. You have to reinterpret the values as uchar. It Means you have to assume that the data bits actually represent an unsigned char, regardless of the type of pointer. It can be done as follows:
uchar* ptr = reinterpret_cast<uchar*>(imageGray->imageData);
ptr[i] = saturate_cast<uchar>(alpha * ptr[i] + beta);
If you are using C++ I am not sure why anybody would want to use IplImage. But your problem is this line
imageGray->imageData[i] = (alpha * input_img->imageData[i]) + beta;
It can overflow. Also imageData is a char*, and a char may be signed or unsigned, you need to make it unsigned. You need use saturate_cast to prevent overflow, and a cast to get rid of the signed char:
imageGray->imageData[i] = saturate_cast<uchar>((alpha * static_cast<uchar>(input_img->imageData[i])) + beta);
You can use this little program to see what is going on:
#include <opencv2/core/core.hpp>
#include <iostream> // std::cout
#include <vector> // std::vector
int main(int argc, char** argv)
{
double alpha = 1.6;
int beta = 50;
std::vector<uchar> z;
for(int i = 0; i <= 255; ++i)
z.push_back(i);
char* zp = reinterpret_cast<char *>(&z[0]);
for(int i = 0; i <= 255; ++i)
std::cout << i << " -> " << int(cv::saturate_cast<uchar>(alpha * static_cast<uchar>(zp[i]) + beta)) << std::endl;
}