Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

Floating point exception when looping and reading images

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.

Floating point exception when looping and reading images

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 wrote the loadImage() method).method in a way where (I hope) the method would not return until the data is complete. It could be wrong, I am just looking for a way to avoid or ignore the Floating point exception.

#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 Sorry for the long code, thanks for any help! First time using opencv.