I'm building a line following robot with OpenCV (c++), Raspberry Pi, Arduino, and an Arducam. I keep getting a Floating point exception when I decrease the delay time between image scans (at the end of the loop in main(), down to a 1 second delay). A bash script simultaneously captures an image from the Arducam, and the c++ program continuously reads the same image file name that's being written over.
At first I thought the exception was thrown because the image file was not finished being written to before it was read, but I tried to write it so the program skips the image processing methods that use floats or uchars if there is missing data. This could still be the problem, but this was the supposed solution for others doing the same thing. Maybe I'm implementing this part wrong? (in the loadImage() method).
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#define ADDRESS 0x04 // The Arduino I2C address
static const char *devName = "/dev/i2c-1"; // The I2C bus
using namespace cv;
using namespace std;
// Line Detection program
// Efficient method to reduce noise
Mat& scanAndReduce(Mat& I, const int* const table)
{
// accept only char type matrices
CV_Assert(I.depth() == CV_8U);
int channels = I.channels();
int nRows = I.rows;
int nCols = I.cols * channels;
if (I.isContinuous())
{
nCols *= nRows;
nRows = 1;
}
int i,j;
uchar* p;
for( i = 0; i < nRows; ++i)
{
p = I.ptr<uchar>(i);
for ( j = 0; j < nCols; ++j)
{
p[j] = table[p[j]];
}
}
return I;
}
// Loads command-line argument image file location
int loadImage(Mat& source, char argv[])
{
while ( !source.data )
{
source = imread(argv, 0);
}
return 0;
}
// Displays input image in new window
void display(Mat& image)
{
namedWindow("Result", WINDOW_NORMAL);
imshow("Result", image);
waitKey(0);
}
// prints 10x10 ellipse with input center and height to input matrix
void drawEllipse(Mat& destination, int center, int lineY)
{
ellipse( destination, // destination matrix
Point(center,lineY), // location
Size(20,20), // size
0, // angle
0, // start
360, // end
Scalar(100,0,0)); // color
}
// Scan bottom half of screen to see where line is
int scanLines(Mat& sourceImage)
{
int diff = (sourceImage.rows) * 0.1; // distance between scan lines
int lineY = (sourceImage.rows) * 0.9; // starting scan line
int vals[sourceImage.cols]; // save line values (left to right)
int center = 0; // sums indexes of dark values
int numDark = 0; // tracks dark values
int offset = 0;
// get values along scan lines
for(int i = 0; i < 5; i++) // traverse y axis (bottom to top)
{
center = 0; // sums indexes of dark values
numDark = 0; // tracks dark values
Scalar intensity;
int leftBound = sourceImage.cols * 0.25;
int rightBound = sourceImage.cols * 0.75;
for(int j = leftBound; j < rightBound; j++) // traverse x axis of image
{
intensity = sourceImage.at<uchar>(Point(j,lineY)); // save value
vals[j] = intensity[0]; // get first value (greyscale)
// save dark value
if(vals[j] < 100)
{
center += j; // add index to sum
numDark++; // increment dark counter
}
}
// calculate center of dark values
center = center/numDark;
offset += center;
// draw center
drawEllipse(sourceImage, center, lineY);
lineY -= diff;
}
offset /= 5;
return offset;
}
void sendToArduino(int val)
{
// connect to Arduino
cout<<"I2C: Connecting"<<endl;
int file;
if ((file = open(devName, O_RDWR)) < 0)
{
cout<<stderr<<"I2C: Failed to access "<<devName<<endl;
exit(1);
}
// get bus
cout<<"I2C: acquiring buss to 0x"<<ADDRESS<<endl;
if (ioctl(file, I2C_SLAVE, ADDRESS) < 0)
{
cout<<stderr<<"I2C: Failed to talk to slave 0x"<<ADDRESS<<endl;
exit(1);
}
unsigned char cmd[16];
// sends data
cout<<"Sending "<<val<<endl;
cmd[0] = val;
if (write(file, cmd, 1) == 1)
{
usleep(10000);
char buf[1];
if (read(file, buf, 1) == 1)
{
int temp = (int) buf[0];
cout<<"Received "<<temp<<endl;
}
}
// Now wait else you could crash the arduino by sending requests too fast
usleep(10000);
close(file);
}
int main( int argc, char** argv )
{
// calculate lookup table. Values are separated at intensity
// split at 100 to make reading values easier when scanning
cout<<"Creating table"<<endl;
int divideWith = 100;
int table[256];
for (int i = 0; i < 256; ++i)
{
table[i] = (int)(divideWith * (i/divideWith));
if(table[i] >= divideWith) table[i] = 255;
if(table[i] < divideWith) table[i] = 0;
}
cout<<"Starting loop..."<<endl;
while(1)
{
// load image
Mat sourceImage, destination;
int imgFound = loadImage(sourceImage,"/home/pi/Documents/ArduCAM4Pi/img.jpg");
if(imgFound == 0)
{
// reduce image resolution to simplify analysis
resize(sourceImage,destination,Size(320,240));
sourceImage = destination;
// Reduce noise
scanAndReduce(sourceImage,table);
// Scan image, find offset from line
int center = sourceImage.cols / 2;
int offset = scanLines(sourceImage);
cout<<"center="<<(sourceImage.cols/2)<<endl;
cout<<"offset="<<offset<<endl;
// if offset > center turn right
if (offset > center)
{
offset = 2;
}
else if (offset < center) // turn left
{
offset = 3;
}
else // go striaght
{
offset = 4;
}
sendToArduino(offset);
imwrite("out.jpg",sourceImage);
}
sleep(1);
}
return 0;
}
Thanks for any help! First time using opencv.