Published in potatoreview magazine

Posted on January 26th, 2012 by Jamie Hutton

In the January/February (2012) addition of potato  review, the TODD system features a two page article:

The authors of a paper to be delivered at Crop Protection in Northern Britain 2012* point out that clear unblemished skin is a significant selling point and that potatoes with surface defects caused by ‘otherwise benign infections’ are strongly avoided by consumers. With most of the crop graded by sight, however, there are inevitable mistakes and wastage.

Tom Duckett and co-workers have developed an inexpensive system for automatic identification of skin defects using what they describe as ‘off-the-shelf hardware’ comprising a low-cost sensor and standard desktop computer equipped with a graphics processing unit (GPU).

The software has been designed to detect and quantify a range of common defects, using image processing and ‘machine learning’ techniques to differentiate between them based on their visual characteristics. It also has an intuitive graphical user interface (GUI) to allow easy set-up by quality control staff. The system can  be programmed to process individual tubers or to produce aggregate data for a sample, summarising the proportions of potatoes carrying common scab, black dot, silver scurf or greening, for example.

Potatoes are placed in a light box equipped with a 10 mega-pixel web-cam. Selected tubers are used to ‘mark-up’ defective and clean areas to train the system, with output displayed as a colour-coded computer screen image along with a summary report giving the percentage area for each of the defect types.

To train the software the operator simply hits the buttons for ‘capture image’ and ‘remove background’. This highlights the tubers after first recording an image of the empty tray. ‘Mark-up’ is performed by selecting a user-defined class or category which will correspond to a particular type of defect. The pixel area which relates to that defect is selected to provide the ‘training data’. Pressing the ‘train classifier’ button completes the process but the system can be quickly re-calibrated for different potato varieties or different skin conditions.

Potato Review

Controlling a KHR3-HV RCB4 with C++

Posted on December 27th, 2011 by Jamie Hutton

Anyone who has a Kondo KHR3-HV will know all the instructions are in Japanese so I am posting a few code snippets. This will hopefully get you started with talking to the Eprom in Windows allowing you to get those servos moving. So once you have connect the Eprom to your USB port your going to want to first establish a  connection via the com port it has been issued. If this is the first time you have connected the board it should be on COM3, however I suggest you look inside your device manager to make sure.

int initCOM(int COMPort){
char myNum[2];
sprintf_s(myNum, "%d", COMPort);
char myCom[5] = "COM";
myCom[3] = myNum[0];
myCom[4] = myNum[1];

if ((commport = CreateFile(myCom, // open com:
GENERIC_READ | GENERIC_WRITE, // for reading and writing
0, // exclusive access
NULL, // no security attributes
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE) {
printf("Error: Can not open COM Port\n");
}

//set comms
comSettings.BaudRate = 115200;
comSettings.StopBits = ONESTOPBIT;
comSettings.ByteSize = 8;
comSettings.Parity = EVENPARITY;
comSettings.fParity = TRUE;

// Set Port parameters.
bStatus = SetCommState(commport, &comSettings);
if (bStatus == 0){
printf("Error: failed to set Comm state.\n");
}

//set timeouts (this is required. to read more than one byte)
commTimeout.ReadIntervalTimeout = 50;
commTimeout.ReadTotalTimeoutConstant = 50;
commTimeout.ReadTotalTimeoutMultiplier = 10;
commTimeout.WriteTotalTimeoutConstant = 50;
commTimeout.WriteTotalTimeoutMultiplier = 10;

bStatus = SetCommTimeouts(commport, &commTimeout);
if (bStatus == 0) {
printf("Error: failed to set Comm timeouts.\n");
}

return bStatus;
}

Above shows a simple connection method, it has some very simple error handling as it is just an example. Next on the list of things you will want to be able to do is send data to the RCB4, before we can do this we need to set up some buffers that are accessible by all methods.

unsigned char INBUFFER[256];
unsigned char OUTBUFFER[256];
unsigned char SERVOS[35];

DWORD bytes_read = 0; // Number of bytes read from port
DWORD bytes_written = 0; // Number of bytes written to the port
HANDLE commport = NULL; // Handle COM port
int bStatus;
DCB comSettings; // Contains various port settings
COMMTIMEOUTS commTimeout;

int returnVal = 0; // Used for the return value of functions

unsigned int FREE_POS = 32768;
unsigned int HOLD_POS = 32767;

The next method shows you how to write and receive data back from the RCB4, this could be achieved with a single buffer. However, for demonstration purposes this way allows you to see both input and output of the RCB4 communication.

/*
* Functon kondo_send - writes byte code instructions to the RCB4
* Also receives the returning ack.
* @param bytesToRead - The number of bytes expecded back from the RCB4
*/

int kondo_send( int bytesToRead ){
bStatus = WriteFile(commport, // Handle
&OUTBUFFER, // Outgoing data
OUTBUFFER[0], // Number of bytes to write
&bytes_written, // Number of bytes written
NULL);
if (bStatus == 0 || (bytes_written != OUTBUFFER[0])){
printf("Error: Could not write to Comm port - DEBUG: %d.\n", bStatus);
}

bStatus = ReadFile(commport, // Handle
&INBUFFER, // Incoming data
bytesToRead, // Number of bytes to read
&bytes_read, // Number of bytes read
NULL);
if (bStatus == 0){
printf("Error: Could not Read from Comm port - DEBUG: %d.\n", bStatus);
}
else {
printf("Received: ");
for(int i = 0; i < bytesToRead; i++){
printf("%X ", INBUFFER[i]);
}
printf("\n");
}
return 0;
}

Now were going to send a simple acknowledgement to the RCB4 and hopefully receive the  positive acknowledgement back as as response, 0×06  or a negative acknowledgement which is 0×15. Another command that is used in this method is the RCB4_CMD_ACK command which is 0xFE. Before you can send the data you must calculate the checksum and include it as the last byte. the checksum is the sum of all the bytes being sent.

/*
* Function kondo_checksum - returns the sum on n-1 bytes of the OUTBUFFER[]
* This function only needs to return the lower byte of the checksum.
* @param UCHAR OUTBUFFER[] - The array of byte codes to send to the RCB4
* @param int nBytes - number of bytes from OUTBUFFER to sum
*/
int kondo_checksum(UCHAR OUTBUFFER[], int nBytes){
unsigned int sum = 0;
// loop and add together bytes beig sent
for(int i = 0; i < nBytes; i++){
sum += OUTBUFFER[i];
}     return sum; }

/* Function kondo_ack - send and receives an acknowledgement from the RCB4 */
int kondo_ack() {
OUTBUFFER[0] = 4;
OUTBUFFER[1] = RCB4_CMD_ACK;
OUTBUFFER[2] = RCB4_ACK_BYTE;
OUTBUFFER[3] = kondo_checksum(OUTBUFFER, 3);
returnVal = kondo_send(4);
if(INBUFFER[2] == RCB4_ACK_BYTE){
return returnVal; // All OK      }
else if(INBUFFER[2] == RCB4_NCK_BYTE){
return -1; // Non-ack but RCB4 present
}
else{
return -2; // No RCB4 connected
}
}

Ok! … well I hope that’s the response you got back. If you did then you can start making other things happen. Lets start with turning the green LED on and off.

/* Function kondo_led switches on/off the RCB4 Green LED
* @param bool isLED - a boolean value true = on; false = off
*/
int kondo_led(bool isLED) {
int light_on = 0;
if(isLED) {
light_on = 128;
}
OUTBUFFER[0] = 9;
OUTBUFFER[1] = 0;
OUTBUFFER[2] = 2;
OUTBUFFER[3] = 0;
OUTBUFFER[4] = 0;
OUTBUFFER[5] = 0;
OUTBUFFER[6] = 31;
OUTBUFFER[7] = light_on;
OUTBUFFER[8] = kondo_checksum(OUTBUFFER, 8);
returnVal = kondo_send(4);
return returnVal; }

This method should turn the green light which is located on the Eprom on when you pass true, and off when you pass false. If that is all working we can move onto addressing and initialising the servos.

/*Function kondo_servo_ID_address - Sets a single servo Address
* @param int Servo_ID - the ID number of the servo
* @param bool SIO - which SIO channel (i.e. false = lower, true = upper)
*/
int kondo_servo_ID_address(int Servo_ID, bool SIO) {
unsigned int servo_address = (Servo_ID*2) * SERVO_SIZE + SERVO_START;
if(SIO) {
servo_address += 20;
}
unsigned int ADDH = (unsigned int) servo_address >> 8;
unsigned int ADDL = (unsigned int) servo_address & 0x00FF;

OUTBUFFER[0] = 0x1B;
OUTBUFFER[1] = 0x00;
OUTBUFFER[2] = 0x02;
OUTBUFFER[3] = ADDL;            // Address L
OUTBUFFER[4] = ADDH;            // Address H
OUTBUFFER[5] = 0x00;
OUTBUFFER[6] = 0x00;
OUTBUFFER[7] = Servo_ID;        // ID of servo
OUTBUFFER[8] = 0x00;
OUTBUFFER[9] = 0x00;
OUTBUFFER[10] = 0x00;
OUTBUFFER[11] = 0x00;
OUTBUFFER[12] = 0x4C;
OUTBUFFER[13] = 0x1D;
OUTBUFFER[14] = 0x00;
OUTBUFFER[15] = 0x00;
OUTBUFFER[16] = 0x00;
OUTBUFFER[17] = 0x00;
OUTBUFFER[18] = 0x00;
OUTBUFFER[19] = 0x00;
OUTBUFFER[20] = 0xFF;
OUTBUFFER[21] = 0xFF;
OUTBUFFER[22] = 0x01;
OUTBUFFER[23] = 0xFF;
OUTBUFFER[24] = 0xFF;
OUTBUFFER[25] = 0x01;
OUTBUFFER[26] = kondo_checksum(OUTBUFFER, 26); // Checksum

returnVal = kondo_send(4);

return returnVal;
}

This method accepts the servo id and a bool for SIO depending on which pin you have the servo connected. If your not sure just send the function once with true and false :) . To activate the servos you have selected you send the following command. It is the same no matter how many, or which servos you wish to activate. If successful after running this command the red light on the back of the servo will illuminate.

/*
* Function kondo_servo_on - This powers on any servos selected
* by the function kondo_init_servo_ID.
*/
int kondo_servo_on( void ){
OUTBUFFER[0] = 0x09;
OUTBUFFER[1] = 0x00;
OUTBUFFER[2] = 0x02;
OUTBUFFER[3] = 0x00;
OUTBUFFER[4] = 0x00;
OUTBUFFER[5] = 0x00;
OUTBUFFER[6] = 0x11;
OUTBUFFER[7] = 0x00;
OUTBUFFER[8] = 0x1C;    // Hardcoded checksum (as this doesn't change)

returnVal = kondo_send(4);

return 0;
}

If the red light has now come on the servo is now ready to move to whatever position you wish.

/**
* Function kondo_set_servo_ID_pos - This function sets the position of
* the servo indexed by IDX to the position set by aPOS.
*
* @param int IDX - the IDX of the servo:
*  note this is NOT its ID but it's count, i.e. servo's 6 are @ 12 & 13
* @param int SIO - to serial IO channel the servo sits on (i.e. 0 or 1)
* @param unsigned int aPos - the position to move the servo to (i.e. 7500)
*/
int kondo_set_servo_ID_pos(int IDX, int SIO, unsigned int aPos) {
IDX = IDX *2;
if (SIO == 1){
IDX++;
}

unsigned int POSH = (unsigned int) aPos >> 8;
unsigned int POSL = (unsigned int) aPos & 0x00FF;

OUTBUFFER[0] = 0x0A;
OUTBUFFER[1] = 0x00;
OUTBUFFER[2] = 0x12;
OUTBUFFER[3] = 0x06;
OUTBUFFER[4] = IDX;
OUTBUFFER[5] = 0x00;
OUTBUFFER[6] = POSL;
OUTBUFFER[7] = POSH;
OUTBUFFER[8] = 0x00;
OUTBUFFER[9] = kondo_checksum(OUTBUFFER, 9);

returnVal = kondo_send(4);

return returnVal;
}

Hopefully everything on this page worked accordingly :) have fun with you new RCB4 robot.

Building Qt 4.8.0 with Intel Compiler

Posted on December 20th, 2011 by Jamie Hutton

Qt has just released the latest version 4.8.0, if you would like to compile this version using an Intel Compiler the steps are listed below.

Requirements

  • Visual Studio 2010 or 2008
  • Intel Compiler 12.1

I assume you will have these two pieces of software already installed, if not do install them now :) .

Downloading Qt 4.8.0

To start you will need to download the source code as a zip by going to the Qt Download page.

qt download page

****Extract the contents of the zip to anywhere you like, but make sure the length of the path is not too long. Otherwise you will get an error randomly throughout your Qt build, and it might happen hours after you started!

NMAKE : fatal error U1077:

Building Qt

You will now need to go to your start bar and open a program called IA-32 Visual Studio 2010 mode.

Intel command prompt 2010

This is a special command prompt which has all the variables set for building with Visual Studio 2010 tools using the Intel Compiler.

You will now need to change directory to the location of the Qt configure.exe. An example of the location of mine is show below.

cd C:\qt-4.8.0\

Once you have done that you need to choose a platform to select win32 with the Intel Compiler simply type:

configure -platform win32-icc

To select a win64 platform with the Intel Compiler, you will want to open the Intel 64 Visual Studio 2010 mode command prompt instead and run:

configure -platform win64-icc

If you want to make a more streamline build you may want to consider some of the following options:

-no-qt3support        //Disables the qt 3 support functionality
-no-opengl            // Disables OpenGL functionality
-mp                   // use multiple processors for compiling
-ltcg                 // This tells the linker to call the compiler
                      // and perform whole program optimization
                      // which may improve performance however
                      // increase the time to build release builds

Now at this point if the console returns:

Perl not found in environment - cannot run syncqt.

You can either go to into the Qt folder and look for a directory called bin and delete these two files:

syncqt
syncqt.bat

Or download and install Perl from ActivePerl *note once you have installed Perl you must close and reopen the Visual Studio 2010 command prompt, and make sure you select the one that starts the Intel Compiler.

Once configure is successful the console will return:

Qt is now configured for building. Just run nmake.
To reconfigure, run nmake confclean and configure.

Finally to build the Qt library type

nmake

This will start building the entire of Qt using the Intel Compiler which takes a little while, possibly 12-16 hours depending on your machine. However, this is normal I suggest you go to sleep!

Setting environment variables

Basically, we are done you now have compiled Qt with an Intel Compiler :) . All you need to do is to set your environment variables (QTDIR and PATH), which tell programs where to find Qt. If you are on Windows 7, you can use the following command to set QTDIR to your installation dir.

setx QTDIR c:\Qt-4.8.0

Also add the Qt/bin to your PATH.

You can now install the Visual Studio Add-in, and start a Qt project.

Enjoy!

Multiple Webcam Frames to High Quality Still Image

Posted on December 17th, 2011 by Jamie Hutton

I am currently experimenting with increasing the capture quality from my Logitech c910 webcam. Just like the Logitech driver I am using bicubic interpolation to improve the resolution of the images captured. This works by capturing multiple frames such as 10 and using all the data in the low-resolution captures to create 1 high resolution image. This process takes a while, however I will be passing most of the process to my GPU to speed up the computation. My aim is to generate a high resolution still image in under 1 second.

Lightbox with black background

Posted on December 15th, 2011 by Jamie Hutton

I purchased some black Faux Suede Fabric yesterday to place in the bottom of my box so I could make the background segmentation more robust, as I won’t have to deal with the shadows anymore.

Lightbox capture

The next steps are to run the lights inside the lightbox off a mains power supply instead of using batteries and possibly changing the LED work lamps with halogens.

NVIDIA Opens Up CUDA Platform by Releasing Compiler Source Code

Posted on December 14th, 2011 by Jamie Hutton

NVIDIA today announced that it will provide the source code for the new NVIDIA® CUDA® LLVM-based compiler to academic researchers and software-tool vendors, enabling  them to more easily add GPU support for more programming languages and support CUDA applications on alternative processor architectures.

The full article can be found at NVIDIA Opens Up CUDA Platform

DirectShow Logitech HD Pro C910 Webcam

Posted on December 13th, 2011 by Jamie Hutton

After hours of trying to set the Exposure, Gain, Brightness, etc. through my C++ program I came across DirectShow which had an example program called PlayCap. In this  I was able to change the resolution of the camera and all the settings except the White balance control which is a bit odd.

Anyway, I have now modified this program and added a windowless vmr for streaming the feed and a frame grabber method I can call from my current OpenCV and Qt project.  Once I have solved the White balance problem I will post up the static library for all to share.

Logitech C910 Webcam

Posted on December 10th, 2011 by Jamie Hutton

I am currently using the logitech C910 HD webcam in my machine vision research. The reason we are using this camera is to keep the current prototype machine vision system low cost. However, to be able to classify multiple object in a single frame a decent resolution was required.

I find the image quality sufficient enough to capture a 300mm by 500mm area. However, the only issue I have with this camera is it constantly resets the settings and attempts to use “smart” software to improve the image quality each time the drivers start when I reopen the program. Unfortunately, this feature stops my system from display a consistent image even inside a specially built light-box to keep the lighting controlled.

If anyone knows of a way to get around this problem please contact me!

Branston ltd Visit

Posted on December 10th, 2011 by Jamie Hutton

On Friday I travel to Branston to demonstrate the latest version of TODD (Trainable Object Defect Detection). This system allows a user to train a classifier by selecting defected areas of produce or items. Once selected, machine learning algorithms are then used to automatically select the best features to distinguish between the selected areas, currently supporting up to 6 classes (these classes can represent any different defect types).

They seemed interested in applying the technology and invited me back in January to test the system in their quality control department working with one of their QC staff members. So, I need to spend the next couple of weeks adding in the feature of storing the trained classifiers in order not to lose all the data I can collect at Branston.

Farmers weekly BP2011 vision article

Posted on December 7th, 2011 by Jamie Hutton

Following the BP2011 event where we showcased our latest prototype of the potato blemish detection system Farmer Weekly have published an article  British-Potato-2011-Auto-blemish-grading-system.