Tutorial on spToolkit

Transcription

Tutorial on spToolkit
Tutorial on spToolkit
A.C. Klaren
August, 2004
2
Chapter 1
Introduction
1.1
The SmartSpectra project
The SmartSpectra project started in 2002 with the objective to design and
develop a multispectral sensor with a set of features that permits its use in
commercial applications. It will be provided with a set of high-level software
tools to simplify its application as a developer’s toolkit for any possible field
of application where multispectral imaging is needed. This set of high-level
software tools has been written in C++ and can be found in a library called
spToolkit.
1.2
The spToolkit library
The spToolkit library contains a number of high-level software tools to facilitate
the process of extracting information from the images obtained by the multispectral camera. All its functions can be applied to images with any number of
bands and to images of various data types. This tutorial will show you how to
create a program in Microsoft Visual C++ 6.0, which will segment an image of
an orange, using multispectral techniques provided by the spToolkit library.
3
4
CHAPTER 1. INTRODUCTION
Chapter 2
Tutorial
2.1
Creating a Windows program
In order to visualize the results, this tutorial explains the use of the spToolkit
in a Windows environment. The Microsoft platform was chosen due to the fact
that most partners in the SmartSpectra project are using this platform. This
section shows how to create an application in Microsoft Visual C++ 6.0 that
creates windows to show images stored in memory in the spToolkit format.
1. Start Microsoft Visual C++ 6.0
2. Click File, and then New
3. Under the tab Projects, choose MFC AppWizard (exe)
4. Type Tutorial as the project name, choose a location (optional)
and click OK
5. A window with the title MFC AppWizard opens. Choose Dialog based
6. Click Finish
7. The window ”New Project Information” opens. Click OK
The result is shown in Figure 2.1
Now that you have created the project, it’s time to adjust it to your needs.
Our objective is to write a program that segments a multispectral image of an
orange. To make things easy, we will integrate the possibility to view images
in a window. The window that you have already created will be the control
window. We will create an other window to show the images.
1. Click with the right mouse button on OK in the Tutorial window
2. Choose Properties
3. Change the Caption from OK to Start
4. Change the ID from IDOK to IDSTART
5. Close the Properties window by click the ”X” on the top right
of the window
5
6
CHAPTER 2. TUTORIAL
Figure 2.1: A screenshot of the new project.
6. Find the folder Dialog in the Resource View on the left and
click on it with the right mouse button
7. Choose Insert Dialog
8. Click on the OK button in the new Dialog window and press
delete
9. Click on the Cancel button and press delete
10. Save the project
Your screen should now look like Figure 2.2. To be able to use this window,
you need to add a class to this dialog window and arrange the destruction.
1. Click with the right mouse button on the Dialog window
2. Choose ClassWizard. The window ”Adding a class ” opens
3. Make sure that ”Create a new class” is selected and click OK
4. Write CImWin as class name
5. Choose CDialog as base class
6. Click OK
7. Look in the list ”Messages” for PostNcDestroy and click Add
Function
8. Click Edit Code
9. write the following code in this function: delete(this);
2.1. CREATING A WINDOWS PROGRAM
Figure 2.2: Created a second window to show the images.
Figure 2.3: The OnNcDestroy function.
7
8
CHAPTER 2. TUTORIAL
10. Save the project
Check if you screen looks like Figure 2.3. Now that you designed a dialog window, added a class and arranged the destruction, it’s time to actually start
writing our own code. To be able to use the toolkit, we will have to insert come
includes and libaries, etc.
1. Open Windows Explorer and go to the folder /spToolkit files
which is part of this tutorial
2. copy spToolkit.dll and 1394camera.dll to your project folder
(/Tutorial)
3. Copy the subfolders /include and /lib to your project folder
4. Go back to Microsoft Visual C++
5. Choose Project in the menu bar and next Add To Project, and
then Files...
6. Double click the folder lib
7. Change Files of Type to All Files
8. Select both files and click OK
9. Choose Project again, and Settings. A window called, Project
Settings, opens
10. Choose the C/C++ tab
11. Change the Category to Preprocessor
12. Write ./include at the Additional Include Directories option
13. Choose the Link tab
14. Change the Category to Input
15. Write ./lib at the Additional Library Directories option
16. Click OK
The Project Settings Window is shown in Figure 2.4. Now continue with
inserting the includes and namespaces.
1. Click the tab FileView on the left side of the screen
2. Double click the file Tutorial.h
3. Insert the following codes at the 10th line: #include ”spToolkit.h”
and using namespace sp;
4. Click File in the menu bar and next Save All
5. Click Build in the menu bar and next Build Tutorial.exe
If the compiling went alright, you’re screen should look like Figure 2.5. Now
you are ready to use toolkit commands. The next step is to write the code
for the CImWin class. The idea is that this class will show RGB images in its
window. First we will modify the standard constructor so that it can receive
toolkit image data.
2.1. CREATING A WINDOWS PROGRAM
Figure 2.4: The Project Settings Window.
Figure 2.5: A successfully compiled project.
9
10
CHAPTER 2. TUTORIAL
1. Click on the FileView tab on the left and double click the file
ImWin.h
2. Look for the standard constructor, and add a parameter so that
it will look this: CImWin(rgb image cl image, CWnd* pParent
= NULL);
3. Now go to the ImWin.cpp file in the same way and add the
same parameter to the standard constructor
4. Now insert the code below this box in this constructor
row=image.GetRows();
col=image.GetCols();
bts = new BYTE[row*col*4];
unsigned int i=0;
for (unsigned int r=0; r < row; r++)
for (unsigned int c=0; c < col; c++) {
for (unsigned int b=0; b < 3; b++) {
// 2-b because windows images are BGR
bts[i] = image(r,c,2-b);
i++;
}
i++;
}
Create(IDD_DIALOG1,pParent);
// The size of the window is bigger than the image due to its borders
MoveWindow(0, 0, col+6, row+25, false);
ShowWindow(SW_SHOW);
5. Go to the function ”void CImWin::PostNcDestroy()” and insert
”delete[] bts;” before ”delete this”
6. Save all
Your screen should look something like Figure 2.6. The constructor has been
written, now it is time to write the actual Painting function which is responsible
for drawing the image on the screen.
1. Click on the ResourceView on the left and double click IDD DIALOG1
2. Click with the right mouse button on the Dialog window and
choose ClassWizard
3. Look in the ”Messages” list for WM PAINT
4. Click Add Function
5. click Edit Code
6. Now insert the following code in the function OnPaint
CDC bmDC; // Create compatible device context
bmDC.CreateCompatibleDC(&dc);
HBITMAP hBmp; // Create bitmap
hBmp=CreateCompatibleBitmap (dc, col, row);
SetBitmapBits(hBmp,col*row*4,bts);
2.1. CREATING A WINDOWS PROGRAM
11
Figure 2.6: The modified constructor.
bmDC.SelectObject(hBmp); //Select bitmap into
dc.BitBlt(0,0,col,row,&bmDC,0,0,SRCCOPY);
compatible dc and show
7. Save all
Your screen should now look like Figure 2.7. The only thing that is still
missing, is the declaration of several variables in the header on this class.
1. Click on the tab ClassView in the left of the screen .
2. Find CImWin in the pull down list and click it with the right
mouse button
3. Choose Add Member Variable. The window Add Member Variable opens
4. Choose in the Variable type box: unsigned int
5. Type in the Variable name box: row
6. Choose Private
7. Click OK
8. Now add unsigned int col in the same way
9. And add BYTE* bts
10. Save all
12
CHAPTER 2. TUTORIAL
Figure 2.7: The OnPaint function.
Figure 2.8: The Add Member Variable window.
2.1. CREATING A WINDOWS PROGRAM
13
Figure 2.9: Including ImWin.
The Add Member Variable window is shown in Figure 2.8. Now you have
finished writing this class. When you call the constructor of an object of this
class, passing on an rgb image, it will automatically create a window and show
the image. We will see that now.
1. Click the tab Resource View on the left side of the screen
2. Find the dialog IDD TUTORIAL DIALOG and double-click it
3. Now double-click the Start button in the Tutorial window. A
window called ”Add Member Function” opens. Click OK
4. A new function has been created in the TutorialDlg.cpp file,
called OnStart. This function will be called whenever the user
clicks on Start
5. Insert the following code:
rgb_image_cl rgb_im(200,200);
rgb_im.Clear(150);
CImWin *iw = new CImWin(rgb_im, this);
6. Scroll to the top of this file and type at the line 7: #include
”ImWin.h”
7. Save all
8. Compile project
If your project compiled successfully, your screen should look like Figure 2.9.
Now it’s time to run your program! Before running it, imagine what you expect
14
CHAPTER 2. TUTORIAL
Figure 2.10: The result!
to see. Press F5 to Run. Figure 2.10 is what I see on my screen, after pressing
Start!
2.2
Load and save multispectral images
This section will show you how you can load images, cast them from one type
to another, extract bands and save them. We will start with loading a PPM
image into an image class of unsigned chars.
1. Remove the following lines from the function OnBnClickedOk:
rgb_image_cl rgb_im(200,200);
rgb_im.Clear(150);
CImWin *iw = new CImWin(rgb_im, this);
2. Replace them by this code:
ubyte_image_cl ub_im;
input_file_cl inp_file("oranges", PPM);
inp_file >> ub_im;
CImWin *iw = new CImWin( (rgb_image_cl)ub_im, this);
3. Save all
4. Press F5 to run the project
5. Click the Start button on your project
2.2. LOAD AND SAVE MULTISPECTRAL IMAGES
15
Figure 2.11: Showing oranges on the screen.
You will now see a photo of an orange tree in your screen, see Figure 2.11.
When we study the few lines of code we just wrote, we’ll see that the casting
function is situated in the last line, casting a ubyte image cl to an rgb image cl.
Let’s expand the number of bands from 3 to 33. We’ll load an ENVI image into
the program’s memory and we’ll choose 3 bands, and show them as an RGB
image on the screen.
1. Remove the 4 lines of code that you entered before and replace
them with:
ubyte_image_cl ub_im;
input_file_cl inp_file("./images/orange_multiband_ubyte", ENVI);
inp_file >> ub_im;
rgb_image_cl rgb_im(ub_im.GetRows(), ub_im.GetCols());
rgb_im.PutBand(ub_im[15],0);
rgb_im.PutBand(ub_im[16],1);
rgb_im.PutBand(ub_im[17],2);
output_file_cl outp_file("./images/output_orange_ubyte", PPM);
outp_file << rgb_im;
CImWin *iw = new CImWin(rgb_im, this);
2. Save all
3. Press F5 to run the project
This little program loaded an ENVI image in its memory, placed 3 of its
bands into an RGB image, writes it to a file and to the screen (see Figure 2.12).
16
CHAPTER 2. TUTORIAL
Figure 2.12: Three bands taken from an ENVI image and shown as an RGB
image.
You have probably been slightly annoyed by the fact that this program took
quite a long time to be executed. This is mainly due to the fact that the ENVI
file is 11 MB big. A solution to the program is to load just the 3 bands that
you really need, instead of all of them. This can be done in the following way.
1. Replace the code:
ubyte_image_cl ub_im;
input_file_cl inp_file("./images/orange_multiband_ubyte", ENVI);
inp_file >> ub_im;
rgb_image_cl rgb_im(ub_im.GetRows(), ub_im.GetCols());
rgb_im.PutBand(ub_im[15],0);
rgb_im.PutBand(ub_im[16],1);
rgb_im.PutBand(ub_im[17],2);
2. ...with this code:
rgb_image_cl rgb_im;
input_file_cl inp_file("./images/orange_multiband_ubyte", ENVI);
inp_file.LoadImage(rgb_im,15,17);
3. Save all
4. Press F5 to run the project
As you will have noticed, the program executes much quicker now. However,
LoadImage can only load a number of successive bands.
2.3. ERROR HANDLING
17
Figure 2.13: An unclear error message.
2.3
Error handling
In this section we will explore the different ways of error detection.
1. Replace the code that you typed in the function OnBnClickedOk with the following code:
rgb_image_cl rgb_im;
input_file_cl inp_file("./images/bird",PGM);
inp_file >> rgb_im;
rgb_im(600,125,1)=255;
CImWin *iw = new CImWin(rgb_im, this);
2. Save all
3. Press F5 to run the project
You should have gotten an error message as shown in Figure 2.13. Normally,
at this moment you would start a long process of searching for the error, debugging, etc. Fortunately, the toolkit has a tool incorporated to look up errors
quickly. It is based on the C++ method ”try-throw-catch”: you try a function,
an error might be thrown which will be caught and handled. Here is how it
works.
1. Add the try and catch function as shown here:
try {
rgb_image_cl rgb_im;
input_file_cl inp_file("./images/bird",PGM);
inp_file >> rgb_im;
rgb_im(600,125,1)=255;
CImWin *iw = new CImWin(rgb_im, this);
}
catch (error_message_cl e) {MessageBox(e.ReturnReport().c_str());}
2. Save all
3. Press F5 to run the project
Obviously you still got an error, but it is not so unclear as it was before.
Now you’re being told that there is something wrong with the number of bands
18
CHAPTER 2. TUTORIAL
Figure 2.14: Still an error message, but with a hint.
of the image. Let’s have a closer look at the program. You have an RGB image,
which obviously has three bands. Then, you try to save a PGM image in it,
which has just one band. The toolkit doesn’t know what to do with the two
remaining bands and throws an error of type error message cl. Let’s adjust the
program to eliminate the error.
1. Rewrite the program as follows:
try {
ubyte_image_cl ub_im; //ubyte_image_cl can have any number of bands
input_file_cl inp_file("./images/bird",PGM);
inp_file >> ub_im;
ub_im.AddBands(2); //expand the image with 2 bands to a total of 3
ub_im.PutBand(ub_im[0],1); //copy the first band into the second
ub_im.PutBand(ub_im[0],2); //copy the first band into the third
ub_im(600,125,1)=255; //change the pixel
CImWin *iw = new CImWin( (rgb_image_cl)ub_im, this);
//don’t forget casting to rgb_image_cl!
}
catch (error_message_cl e) {MessageBox(e.ReturnReport().c_str());}
2. Save all
3. Press F5 to run the project
A new error occurred, saying that the requested row number is higher than
the available number of rows. The problem appears to be related to the part of
de code where we assign a new value to the pixel at row=600, column=125 and
band=1. The image does not have 600 rows, which explains the error.
1. Change this line of code:
ub_im(600,125,1)=255;
2. into this:
ub_im(60,125,1)=255;
3. Save all
4. Press F5 to run the project
If all went well, you did not get any errors and the bird has a little dot in
his eye (see Figure 2.16). The moral of the story: don’t forget to use try/catch
when you use toolkit instructions!
2.3. ERROR HANDLING
19
Figure 2.15: Another error.
Figure 2.16: The result.
20
CHAPTER 2. TUTORIAL
Figure 2.17: The cropped image.
2.4
Performing image operations
Now it is time to actually do something with our images! As said before, the
goal of this tutorial is to perform a segmentation on a multispectral image of
an orange. To avoid a long processing time, we’ll crop the image, concentrating
on the part that really matters.
1. Replace the code that you typed in the function OnBnClickedOk with the following code:
ubyte_image_cl ub_im;
input_file_cl inp_file("./images/orange_multiband_ubyte",ENVI);
inp_file >> ub_im;
ub_im.Crop(100,200,400,500);
CImWin *iw = new CImWin( (rgb_image_cl)ub_im, this);
//casting to RGB results in showing only the first 3 bands
2. Save all
3. Press F5 to run the project
The image has become smaller, only showing the most interesting part. See
Figure 2.17. We will now threshold the image. Since it is a multispectral image,
we need to give a threshold value for every band. This is done by means of a
vector. To keep things simple, we give the same value for every band.
1. Insert the following code after the line of code where you crop
the image.
vector<unsigned char> v(ub_im.GetBands(), 50);
ub_im = ub_im.Thresholding(v);
// Copy the first band into the second and third
// to create a gray RGB image.
ub_im.AddBands(2);
ub_im.PutBand(ub_im[0],1);
ub_im.PutBand(ub_im[0],2);
2. Save all
2.4. PERFORMING IMAGE OPERATIONS
21
Figure 2.18: The segmented image.
3. Press F5 to run the project
The result is shown in Figure 2.18. This simple thresholding function did a
pretty good job segmenting the defects of the orange. By adjusting the thresholding values for every band, the results can easily improve. You can try that
yourself.
Now we will detect the borders of the segmented image, using convolution. We
will use a convolution kernel for horizontal edge detection and one for vertical
edge detection. Then, we will combine those results into one image.
1. Insert the following code after the line of code where you threshold the image.
//create both kernels and perform the convolution
gray_ubyte_image_cl gub_im_x, gub_im_y;
mask_cl mask1(Sobel_x);
gub_im_x=ub_im.Convolution(mask1);
mask_cl mask2(Sobel_y);
gub_im_y=ub_im.Convolution(mask2);
// Create a real image and use it to write the results to
gray_real_image_cl gr_im(ub_im.GetRows(), ub_im.GetCols());
for (unsigned int r=0; r<gr_im.GetRows(); r++)
for (unsigned int c=0; c<gr_im.GetCols(); c++)
gr_im(r,c)=sqrt(pow(gub_im_x(r,c),2)+pow(gub_im_y(r,c),2));
// Normalize the image and cast it to ubyte_image_cl
gr_im=gr_im.Normalization(0,255);
ub_im=(ubyte_image_cl) gr_im;
2. Save all
3. Press F5 to run the project
The result (shown in Figure 2.19) is not very impressive. This is due to the
amount of noise present in the thresholded image. There are various techniques
22
CHAPTER 2. TUTORIAL
Figure 2.19: Edge detection.
to improve the result, like e.g. region growing. However, this is not further
discussed in this tutorial and neither is it available in the toolkit (yet).
2.5
Band selection
Working with multispectral bands is usually very time consuming, especially
when the image has a large number of bands. Try the following program and
clock the time it takes to execute (It could take up to half an hour).
1. Replace the code that you typed in the function OnBnClickedOk with the following code:
// Load the source image
ushort_image_cl us_im;
input_file_cl inp("./images/sp_orange_20_b_vis", ENVI);
inp >> us_im;
// Transform the image from 12 bit to 8 bit
ubyte_image_cl ub_im;
ub_im = (ubyte_image_cl) (us_im/16);
// Only use the part of the image that shows the orange
ub_im.Crop(100,150,400,550);
// Scale the image to reduce the classification time
ub_im=ub_im.Scale(0.4, 0.4);
// Load the trainingset
ubyte_image_cl training;
input_file_cl training_file("./images/training", ENVI);
training_file >> training;
// Perform the 1-NN classification
gray_ubyte_image_cl label(ub_im.GetRows(), ub_im.GetCols());
label.Clear();
double d;
2.5. BAND SELECTION
23
for (unsigned int r=0; r<ub_im.GetRows(); r++)
for (unsigned int c=0; c<ub_im.GetCols(); c++) {
double len=1000; // start with a great length
// Determine the distance from the pixel to every prototype
for (unsigned int rr=0; rr<training.GetRows(); rr++)
for (unsigned int cc=0; cc<training.GetCols(); cc++){
d = dist(ub_im.GetPixel(r,c),training.GetPixel(rr,cc));
if (d < len) {
// give this pixel the label of the closest neighbour
label(r,c)=training(rr,cc,training.GetBands()-1);
len = d;
}
}
}
// Save the label file
output_file_cl out("label\_all\_bands", PGM);
out << label;
// Copy the first band into the second and third to create a gray RGB image.
ub_im = label;
ub_im.AddBands(2);
ub_im.PutBand(ub_im[0],1);
ub_im.PutBand(ub_im[0],2);
CImWin *iw = new CImWin( (rgb_image_cl)ub_im, this);
2. Now include the following function in you project. Place this
function above the function OnBnClickedOk.
double dist(ubyte_pixel_tp c1, ubyte_pixel_tp c2) {
//Determine the distance between c1 and c2
double sum=0;
for (unsigned int b=0; b<c1.GetBands(); b++)
sum += pow(c2[b]-c1[b],2);
return sqrt(sum);
}
3. Save all
4. Press F5 to run the project
As you have probably guessed, this program is a 1-NN classifier. I determines the distance between a multispectral pixel of the source image and every
prototype in the trainingset. Next, it labels this pixel with the same class as
the nearest prototype belongs to. The result is shown in Figure 2.20.
Since our image has 33 bands, this is a very costly process. Especially if you
consider that you might need to repeat this process all the time, which would
be the case with classifying oranges in a warehouse!
It would safe a lot of time if you could reach a similar result with just a part of
those bands. This is what the band selection function does; it selects the bands
that together contain a large amount of information and simultaneously are the
least mutually correlated. The band selection process is time-consuming, but
consider that it only has to be performed once to know which bands are most
24
CHAPTER 2. TUTORIAL
Figure 2.20: The result of the classification process (black=background;
gray=orange; white=overripe).
useful for the type of classification that you are interested in. Clock the time
again and compare the result with the previous result.
1. Add the following code behind the part where you transformed
the image ub im from 12 bit to 8 bit:
// Perform band selection
ub_im = ub_im.BandSelection(3);
2. Add the following code behind the part where you load the
training file into the image training:
// Pick the previously selected bands from the trainingset
ubyte_image_cl training_temp(training.GetRows(),training.GetCols(),4);
vector<unsigned int> sb;
sb = ub_im.GetSelectedBands();
training_temp.PutBand(training[sb[0]],0);
training_temp.PutBand(training[sb[1]],1);
training_temp.PutBand(training[sb[2]],2);
training_temp.PutBand(training[training.GetBands()-1],3);
training = training_temp;
3. Change the output file name from label all bands to label sel bands.
4. Save all
5. Press F5 to run the project
As you can see, the result is very similar to the previous result. The band
selection function is unsupervised and can therefore be used in any situation.
There is another reason that explains the slowness of this program. The images
are stored in memory according to the Band Sequential format (BSQ). That
means that bands are stored one after another, in contrast to Band Interleaved
by Pixel (BIP). BIP means that multispectral pixels are stored one after the
other. In the classification program shown above, multispectral pixels are repeatedly asked for. Due to the BSQ format used in the toolkit, these pixels
have to be built every time. Obviously, this is very time-consuming. A solution
would be to create the pixels one time and store them for further use.
2.6. USING A FIREWIRE CAMERA
25
Figure 2.21: The result of the classification process using band selection
(black=background; gray=orange; white=overripe).
2.6
Using a Firewire camera
The toolkit is designed to work with Firewire cameras with D-cam specification, including the SmartSpectra camera system. In this version of the toolkit
the interface to the SmartSpectra camera system is not activated yet, but the
general interface to Firewire cameras is. In this section we will find out how to
use the camera, how to communicate with it and how to take photos.
Before you start this section, you should be sure that the camera driver has
been properly installed and the camera is plugged in.
1. Place the following code into the function OnBnClickedOk:
ubyte_image_cl ub_im;
camera_cl cam;
cam >> ub_im;
//
//
//
//
if
{
The camera constructor determines automatically
which video mode your camera can handle.
Therefore, it is not sure if the result will
contain 1 band (gray) or 3 bands (color)
(ub_im.GetBands() < 3)
ub_im.AddBands(2);
ub_im.PutBand(ub_im[0],1);
ub_im.PutBand(ub_im[0],2);
}
CImWin *iw = new CImWin( (rgb_image_cl)ub_im, this);
2. Save all
3. Press F5 to run the project
With some cameras you’ll get a black or gray image. This could be caused
by the fact that they need a ”warming up” period. Later on in this section a
method will be introduced that captures several images in a row. This could
26
CHAPTER 2. TUTORIAL
solve the problem, because it allows you throw away the first couple of images
and use the last one.
You can find out in which video mode your camera is running.
1. Add the following code behind the part where you read the
image from the camera into ub im:
stringstream ss;
ss << "Format: " << cam.GetVideoFormat() << endl
<< "Mode:
" << cam.GetVideoMode() << endl
<< "Rate:
" << cam.GetVideoFrameRate();
MessageBox(ss.str().c_str());
2. Save all
3. Press F5 to run the project
A very important part of the camera cl class are the ControlRegisters. These
registers handle the different features of the camera, like the shutter, gain, sharpness, etc. These registers are of type C1394CameraControl, which has the
following functions:
Construction
C1394CameraControl()
virtual C1394CameraControl()
Values
void GetValues() // gets current values from camera
void SetValues() // sets values
Modes
void TurnOn(bool on) // turns a feature on (true) or off (false)
void SetOnePush() // sets the one-push auto-mode command
void SetAutoMode(bool on) // sets the auto-mode (true) or manual-mode
(false)
Status
void Inquire() // updates feature availability
void Status() // updates current values
Image that you would like to know if you can adjust the shutter speed of your
camera. You would like to know if this control function is present in your camera, if it can be turned on and off and what its minimum and maximum allowed
values are.
1. Add the following code behind the last part you added:
// You need to call the function Inquire() to update the values
cam.ControlShutter().Inquire();
stringstream ss2;
ss2 << "Present:
" << cam.ControlShutter().m_present << endl
<< "On/off:
" << cam.ControlShutter().m_onoff << endl
2.6. USING A FIREWIRE CAMERA
27
<< "Value_min: " << cam.ControlShutter().m_min << endl
<< "Value_max: " << cam.ControlShutter().m_max << endl;
MessageBox(ss2.str().c_str());
2. Save all
3. Press F5 to run the project
Now let’s find out what the current value is and change it.
1. Add the following code behind the last part you added:
// You can update by using Status() or GetValues()
cam.ControlShutter().Status();
int old_value, new_value;
old_value = cam.ControlShutter().m_value1;
cam.ControlShutter().m_value1 = 200;
cam.ControlShutter().SetValues();
new_value = cam.ControlShutter().m_value1;
stringstream ss3;
ss3 << "Old value:
" << old_value << endl
<< "New value:
" << new_value;
MessageBox(ss3.str().c_str());
2. Save all
3. Press F5 to run the project
Luckily, writing values to these registers can be done in an easier way:
1. Replace the following code:
cam.ControlShutter().m_value1 = 200;
cam.ControlShutter().SetValues();
2. by this code:
cam.SetShutter(200);
3. Save all
4. Press F5 to run the project
As mentioned before, there is another capturing method. This method captures a certain number of images in a row at high speed. They are all saved in
one multispectral image structure.
1. Now replace all the code you wrote in this section by:
ubyte_image_cl ub_im;
camera_cl cam;
cam.Acquisition(10,ub_im);
//Move the last three bands to the first bands
//They will be shown on the screen
ub_im.PutBand(ub_im[ub_im.GetBands()-1],2);
ub_im.PutBand(ub_im[ub_im.GetBands()-2],1);
ub_im.PutBand(ub_im[ub_im.GetBands()-3],0);
CImWin *iw = new CImWin( (rgb_image_cl)ub_im, this);
28
CHAPTER 2. TUTORIAL
2. Save all
3. Press F5 to run the project
If the resulting image is to dark or to bright, you might want to adjust the
shutter.
Practically all the functions available in the camera driver are also available
in the toolkit. This is because there are situations in which it is more convenient to use those than the higher level functions of the toolkit. However, this
subject is not being dealt with in this tutorial.
2.7
Other functions
There are still a number of functions that have not been treated in this tutorial.
In this section we will write one program that shows several functions at the
same time.
First we’ll introduce the Region Of Interest (ROI). It is one of the constructors of the image classes, which allows you to construct a copy of another image
(or part of another image). The difference with the copy constructor is that
the ROI image doesn’t have its own memory. It actually points to the memory
of the source image. As a consequence, if you change the appearance of a ROI
image, its source image will change as well.
1. Place the following code into the function OnBnClickedOk:
ubyte_image_cl ub_im;
input_file_cl inp_file("./images/oranges",PPM);
inp_file >> ub_im;
// create a region of interest (ROI)
ubyte_image_cl roi(ub_im,10,70,80,80);
// rotate the region of interest
roi=roi.Rotate(90);
// Show the region of interest
CImWin *iw1 = new CImWin( (rgb_image_cl)roi, this);
// Notice that the source image changes as well
CImWin *iw2 = new CImWin( (rgb_image_cl)ub_im, this);
2. Save all
3. Press F5 to run the project
With the toolkit you can calculate the Shannon Entropy of any multispectral
image. The entropy is a measure for the amount of information that an image
contains.
1. Extend your program with the following code:
// Calculating the entropy of this image (measure of information)
stringstream ss;
ss << "The Shannon Entropy of ub_im is: " << ub_im.ShannonEntropy(256);
MessageBox(ss.str().c_str());
2.7. OTHER FUNCTIONS
29
Figure 2.22: The ROI image.
Figure 2.23: The source image that was used to create the ROI.
2. Save all
3. Press F5 to run the project
It takes about a minute to calculate the entropy. As a absolute number the
entropy doesn’t mean much, but you can use it to compare the information of
one image with another. Let’s threshold the image and calculate the entropy
again. Do you expect it to be higher or lower?
1. Extend your program with the following code:
// threshold the image and show it on the screen
vector<unsigned char> v(ub_im.GetBands(), 50);
ub_im = ub_im.Thresholding(v);
// change the 1 band label image into a 3 band image
ub_im.AddBands(2);
ub_im.PutBand(ub_im[0],1);
ub_im.PutBand(ub_im[0],2);
CImWin *iw3 = new CImWin( (rgb_image_cl)ub_im, this);
// Now calculate the entropy again. What do you expect to see?
stringstream ss2;
ss2 << "The Shannon Entropy of the thresholded ub_im is: " << ub_im.ShannonEntropy
MessageBox(ss2.str().c_str());
2. Save all
30
CHAPTER 2. TUTORIAL
3. Press F5 to run the project
2.8
epilogue
You have reached the end of the tutorial. You have been introduced to a number of basic operations to give you a basic understanding of how the toolkit
works. However, more functions will be added to the toolkit and consequently,
the tutorial will be updated too.
If you have any questions of comments, you can send them to [email protected].
Good luck with your multispectral image processing!