Reading and processing images (opencv/c++) - c++

My project is recognizing faces from images. The images have the same name and change occasionally
So i want to load and process the images every time they change
how can i modify this:
while (image==NULL) {
image = cvLoadImage("ayman.jpg", 1);
}
cout << endl << "My image was finally loaded!";
sorry for my english

Ok, let's assume than your images are different at the moment they change (random). How do we detect that it's another image, different from the previous one?
We are going to extract 3 features of your image and it is: the mean of the RED CHANNEL, GREEN CHANNEL and BLUE CHANNEL (it's a vector). So, if the image is the same, the 3 means are the same, but if it's different, the image has been changed.
So think we are in a infinite loop (your while).
while(true) {
// we are going to say here if the image has changed or not
}
Are we ok ? So this is the code:
image = cvLoadImage("ayman.jpg", 1);
Scalar meanOfImage = mean(image);
while (true) {
Scalar meanAtThisMoment = mean(image);
// This are the three features (it's in real one, but one vector of 3).
// We are going to compare the three to be more clear.
if (meanAtThisMoment[0] == meanOfImage[0]
&&
meanAtThisMoment[1] == meanOfImage[1]
&&
meanAtThisMoment[2] == meanOfImage[2]) {
cout << endl << "The image hasn't been changed yet.";
image = cvLoadImage("ayman.jpg", 1); // added!! forgot this, sorry
} else {
cout << endl << "The image has been changed!!!";
// and now we set the meanOfImage (the main mean) of the new image to compare with the future images.
meanOfImage = meanAtThisMoment;
}
}

Related

Pixel values are partially readable

I took an image and I wanted to write the image as its corresponding pixel values and I have done the code and it compiled but the problem is that, I stored those values in a txt file and I copied those values to an excel sheet and what I see is that the pixel values that I got are only for half of the picture i.e when I see it as a whole picture the pixels show me the half the picture or less I dont know, but it isnt showing me the complete picture.
Help me.
#include <opencv2/opencv.hpp>
using namespace cv;
#include <fstream>
using namespace std;
int main()
{
Mat colorImage = imread("/home/bmit/display_image/CIRCLE.jpg");
// Open the file in write mode.
ofstream outputFile("name.txt");
// Iterate through pixels.
int r, c;
for (r = 1; colorImage.rows > r ;r++)
{
for (c = 1; colorImage.cols > c ; c++)
{
int pixel = colorImage.at<uchar>(r,c);
outputFile << pixel << '\t';
}
outputFile << endl;
}
// Close the file.
outputFile.close();
return 0;
}
There are a number of errors which I think are adding up to create this issue. The first is that for a colour image, there isn't really a single "pixel value" - there is a red component, a green component, a blue component (and possibly an alpha channel as well). I'm going to assume from this point onwards that you actually want the BGR values for each pixel sequentially.
cv::Mat is generally a wrapper around a pointer to a large singular block of continuous memory (it isn't always continuous but usually is). The Mat.at<typename>() method is one of the ways of accessing this data, using the typename to interpret it and cast the data accessed.
The issue you are having is the total information stored in this matrix is more than row*cols of uchars. The matrix is storing row*cols*3 trios of blue,green, and red uchars. The line of code int pixel = colorImage.at<uchar>(r,c); is accessing some point in this data sequence based on the size of a uchar, the number of rows in the image, and the values of r & c.
For instance, at some point in the innerloop you will call int pixel = colorImage.at<uchar>(r,c); when r is equal to the number of rows and c equal to the number of columns. You want this value of pixel to be the "pixel value" of the lower right pixel, but what you are actually getting is the value of one of the channel values for a pixel about a 3rd of the width along and a 3rd of the height down the image.
To fix this you have a number of options. I think you'll find reading some of the tutorials on the OpenCV website (this one probably being the most relevant) useful. But if you replace the loop in your code with the following it should work, although I haven't tested it.
for (r=0;r<colorImage.rows; r++)
{
for (r=0; c<colorImage.cols; c++)
{
Point3_<uchar> pixel = colorImage.at<Point3_<uchar>>(r,c);
outputFile << pixel.x << '\t'<< pixel.y << '\t'<< pixel.z << '\t';
}
outputFile << endl;
}
Note that this will be in order BGR, if you require RGB just swap the order of pixel.x & pixel.z

How can I remove a set of pixels from a video with c++?

I have code written that will take a video and output each frames pixel values to a text file, but what I’m having a hard time figuring out is out is how to remove a set of pixels (16x16 pixels section) of a video THEN output to a text file. I feel like I’m missing 1-3 lines of code that will do this.
Everything I’ve tried doesn’t compile.
​//get every data value per frame
​​for (int r = 0; r < frame.rows; r++)
​​{
for (int c = 0; c < frame.cols; c++)
{
​​​​ grayValue = frame.at<uchar>(r, c);
output << grayValue << " ";
}
​​​ output << endl << endl;
}
I get errors for everything I do. Something needs to be added to this loop to remove a 16x16 px of this video before it exports

OpenCV Prediction

Good evening everyone,
I have tried to use this
Keep in my that my Ptr variable is of type BasicFaceRecognizer as per OpenCV 3.0 documentation: http://docs.opencv.org/master/db/d7c/group__face.html#gsc.tab=0
Ptr<BasicFaceRecognizer> model;
int label = -1;
double confidence = 0.0;
this->imageManager = pManager;
this->model = createEigenFaceRecognizer();
this->model->train(pManager->getOpenCVTrainImages(), pManager->getTrainLabels());
for(Mat& imageToTest : pManager->getOpenCVTestImages())
{
this->model->predict(imageToTest, label, confidence);
cout << "Class: " << label
<< " The confidence predicted towards the test image is: " << confidence << endl;
}
When running this code, it correctly identifies the label (which is a good thing) however, if the test image is run against a subset not part of its class I was expecting to receive a class of -1 or a really LOW confidence.
In this example I have not set the face recognizer to 10 PCA components and I did not set a threshold. However, I have tried to run it with a createEigenFaceRecognizer(10, 123.0) or createEigenFaceRecognizer(10, 50.0) or createEigenFaceRecognizer(0, 1.0)...
All of the above return me a confidence of 0. Which seems very unlikely or impossible I was expecting at least a few numbers.
What am I doing wrong, is this a bug?

Draw trajectories of objects in a video using annotations! [OpenCV]

I have several videos about 5 minutes each along with annotation data containing information about each object's bounding box coordinates at each frame number.
I am trying to read the videos and draw lines between center of bounding boxes frame by frame (when the current frame number matches the number from the ground truth data). I don't want to do this in a batch process, but every 30 or 60 frames would work for me.
Here is my code:
VideoCapture capture(path_video);
if (!capture.isOpened()){
cout << "Failed to capture frame/Open the file" << "\n";
return 0;
}
bool stop(false);
while(!stop){
capture >> frame;
if (frame.data==NULL) {
break;
}
double rate = capture.get(CV_CAP_PROP_FPS);
int delay = 1000/rate;
frmNum = (capture.get(CV_CAP_PROP_POS_FRAMES));
for (int i=0 ; i<db.size() ; i++){//db is a vector of vector that has annotation data for each object splited in inner vectors , and is sorted ascendingly on start frame number of objects.
if (!db[i].empty()){
for (int j=1 ; j<db[i].size() ; j++){
if(frmNum == db[i][j-1].currFrame){
cv::line(frame, db[i][j-1].pnt, db[i][j].pnt,Scalar(255,0,0),2);
}
else{
break;
}
}
}
}
imshow("Video", frame);
int key = waitKey(delay);
if (key==27){
break;
}
I checked and my if condition becomes true but no line is drawn on the video. I guess I don't see the lines because frames are changing and the drawn lines are cleared by new frames, But I couldnt come up with an alternative way. Thanks for your help.
If you want to draw the annotations on every frame and you don't mind that the information may be "obsolete" in some cases, I would do the following:
have a global image variable called "overlay" which would hold the most up to date (in regards to current frame number) representation of annotations and would have the same size as a single frame from the videostream
maintain an array of indices called "last_object_annotation_idx", which would store for each object the last index of its annotation already seen/used (initially set to -1 for each object)
in each iteration of the main loop, update the "last_object_annotation_idx" array (that is, for each object check if the current frame number matches the "currFrame" field of the next annotation - I am using the information that the array of annotations is sorted)
if there was a change to the array, redraw the overlay image using annotations referenced from "last_object_annotation_idx"
finally, add the overlay image to the frame and display the result.
Also, in the if statement
if(frmNum == db[i][j-1].currFrame){
cv::line(frame, db[i][j-1].pnt, db[i][j].pnt,Scalar(255,0,0),2);
}
else{
break;
}
isn't the "break" kind of wrong? It means you will break out of the loop if the first check fails, so you will not see anything past the first index in that case.

C++, Access Violation using OpenCV to get RGB value of pixel

I'm trying to use OpenCV to find the RGB values of a pixel in an image. so far I've tried the following:
int blue = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 0];
int green = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 1];
int red = ((uchar *)(img->imageData + y*img->widthStep))[x*img->nChannels + 2];
int blue = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0];
int green = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1];
int red = ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2];
CvPoint pt = {5,5};
uchar* temp_ptr = &((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3];
int blue = temp_ptr[0];
int green = temp_ptr[1];
int red = temp_ptr[2];
But in all of the above, I get the same error:
Unhandled exception at 0x00f5104f in test.exe: 0xC0000005: Access violation reading location: 0x00000048
The last hex number (0x0...48) never changes. I looks like this can be caused by writing further than the bounds of an array. So I've run each of the examples in isolation without any other code at all, and still get the same error. What is causing this error and how can I fix it?
Extra info: Windows 7, MSVC 2010 Express, OpenCV 2.1
--UPDATE--
I've realised the above code is more compicated than it needs to be, so I took the snippet provided by karlphillip (thanks!) as a base and used a similar method. I'm still getting an error, and this time in an even stranger place:
IplImage *slice = cvLoadImage("test.png");
int bpp = slice ->nChannels;
The error occurs on the second line, and is still an Access Violation. There is no code executed before this to do with OpenCV, just some variable initializations. 'test.png' is just a 7*7 pixel 'X' I made in paint to test this out, using a .jpg has hte saem result.
To make sure I hadn't installed OpenCV improperly, I used this code (copied from below) in isolation:
int main ()
{
IplImage* pRGBImg = cvCreateImage(cvSize(5,5),IPL_DEPTH_8U,3);
int width = pRGBImg->width;
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels;
cvNamedWindow("Image view", 1);
cvShowImage("Image view", pRGBImg);
cvWaitKey(0);
cvDestroyWindow("Image view");
for (int i=0; i < width*height*bpp; i+=bpp)
{
if (!(i % (width*bpp))) // print empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<
" G:" << (int) pRGBImg->imageData[i+1] <<
" B:" << (int) pRGBImg->imageData[i+2] << " ";
}
}
This didn't return any errors, but I did get some possibly strange results, here are the first few lines of console output:
R:13 G:-16 B:-83
R:-70: G:13 B:-16
R:-83 G:-70 B: 13
Negative RGB values? Is this to be expected, or is even this not working. If it is normal, then the image I'm loading ('test.png') must be the problem. But, what am I doing wrong if a simple request for the number of channels causes an access violation?
Without knowing the size of the image and how you are looping through it to read its pixels, its impossible to tell what you are doing wrong. Most probably you are trying to read beyond the image boundaries (therefore, access violation).
Anyway, you could add debugs to your code and pinpoint the exact line that triggers this error.
This is how I usually do to iterate through the pixels of an image:
IplImage* pRGBImg = cvLoadImage(input_file.c_str(), CV_LOAD_IMAGE_UNCHANGED);
int width = pRGBImg->width;
int height = pRGBImg->height;
int bpp = pRGBImg->nChannels;
for (int i=0; i < width*height*bpp; i+=bpp)
{
if (!(i % (width*bpp))) // print empty line for better readability
std::cout << std::endl;
std::cout << std::dec << "R:" << (int) pRGBImg->imageData[i] <<
" G:" << (int) pRGBImg->imageData[i+1] <<
" B:" << (int) pRGBImg->imageData[i+2] << " ";
}
The problem probably caused by
IplImage *slice = cvLoadImage("test.png");
if the function failed, variable slice will be NULL, and any further dereferencing will leads to access violation.
Since opencv's dll may be installed on different path than your running application, it is advisable to provide "absolute file path" when calling opencv's function.
Try copy your sample image to c:\, and change your code into IplImage *slice = cvLoadImage("c:\\test.png");, I'd bet it will work like magic :)
Edit:
For your odd pixel values, it might caused by uninitialized memory contents
Try simplyfing the expression a little.
Get a pointer the image data, then calculate a pointer to the start of that row, then a pointer to the pixel, then the R,G,B values
As Martin says, precalculate things like your base addresses and offsets so you can more easily see what is going on. This is very important with pointer arithmetic (e.g. if img->ImgData is not a pointer to a byte-sized data type, your pointer arithmetic will be entirely wrong. Indeed, you appear to be indexing the same array (img->imageData) as both a pointer to uchar and a pointer to float...what is it?)
Also, check the inputs - Are you using a 24bpp or 32bpp test image? Is 'img' non-null? Are x,y coming in within the pixel-width and pixel-height ranges? Is widthStep sane, and expressed in terms of bytes? Stick lots of debugging ASSERTs in your code and you'll eliminate the possibility of a lot of simple errors occurring.
I have created a super safe, automatic garbage collection, very fast, IplImage wrapper using boost::shared_ptr.
The image structure is called blImage and is available at:
http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/
There you can download my blImageAPI and start having fun with opencv instead of sweating about pixel access.
Good luck and have fun creating image algorithms