Chapter 1: Introduction to Magick++
I have been preparing programs that demonstrate the various capabilities of Magick++. I am planning to prepare them as a set of articles that would demonstrate how Magick++ could be integrated in to your C++ program, thus providing an immense power in manipulating images. In this tutorial, I would introduce some of the basics of Magick++ and in the next tutorial, we will discuss methods to compile a Magick++ program. Subsequently, we would prepare simple programs and with advanced features appearing as we progress.
What is ImageMagick API? ImageMagick is a software suite for reading, writing and manipulating images in command line. It is also built-in with APIs in many different programming languages like Ada, C, C++, .NET, Java, PHP, Ruby etc. These APIs allow production of complex image processing operation and a better integration in to programs than command line tools. The various APIs available are listed below along with their programming language. Programming language Ada C Ch COM+ C++ Java LabView Lisp .NET Pascal Perl PHP PHP Phyton Ruby Tcl/Tk API G2F MagickWand ChMagick ImageMagickObject Magick++ JMagick LVOOP ImageMagick CL-Magick MagickNet PascalMagick PerlMagick MagickWand for PHP Imagick PhytonMagick RMagick TclMagick
Why ImageMagick API? Even though the information given below was discussed in one of my previous article, for sake of completeness, I would like to discuss the reasons for existence of ImageMagick API like Magick++.
1. Command line tools do not lend themselves to large programs. 2. The number of file formats are finite and definitely only a few of them are used universally. But the number of image processing operations are infinite as the individual operations can be mixed and matched. Hence, the programmer needs flexibility in creating their own image processing routines. ImageMagick fills this gap by providing APIs. 3. APIs also allow access to the individual pixels in an image and hence can perform low level image processing operations as well. 4. Two people are not alike and definitely two programmers are not alike. So, ImageMagick provides a multiple choice for programming environment. A Java developer need not be constrained to use C++ for his image processing operations. 5. This also allows ImageMagick to be used in different environment, a) Desktop applications using C, C++, LabView, Pascal and Tcl/Tk b) Internet based applications using COM+, Java, .NET, PHP, Python and Ruby
Magick++ Magick++ is a set of C++ class that allows reading, writing and manipulating images from various file formats. Specifically, Magick++ provides 11 major classes to perform these functions. These classes allow 1. Reading and writing images 2. User to create new images 3. Create vector graphics like circle, lines etc in an image 4. Provide ability to manipulate the pixel values in an image 5. Perform image processing operations on the image like filtering, segmentation etc
Magick++ like ImageMagick can be used with almost all major operating systems like Windows, MacOSX, *nix etc. ImageMagick and Magick++ are released under a license compatible with GPL and hence provides free usage for personal and commercial purpose. It
prohibits redistribution of code without prior attribution. Magick++ can be used as a standalone program for your image processing need or can be combined with other libraries to create commercial grade applications. All the subsequent article were written with ImageMagick and Magick++ version 6.2.5 and compiled using the c++ compiler under Linux. So far, we have discussed the basics of Magick++. In the next chapter, we will look at the basics of a Magick++ program and methods for compiling the code. We will specifically focus on parts of the program that needs to be included for successful compilation, methods to link the Magick++ libraries etc.
Chapter 2: Compiling Magick++ program In this chapter, we will look at a demonstration program to understand the method for compiling and linking a Magick++ program. In all the subsequent chapters, programs will be displayed inside a box and will also be italicized to differentiate from the surrounding text. The line numbers would also be provided for easy reference. Parts of the code will also be highlited depending on the discussion pertinent to that chapter. Parts of a Magick++ program Here is an example of a simple program in Magick ++ to read and write an image file.
1. #include 2. #include 3. using namespace std; 4. using namespace Magick; 5. 6. int main(int argc,char **argv){ 7. 8. //Create an instance of the class 9. Image master; 10. 11. //Read the inputfile 12. master.read(argv[1]); 13. 14. //Display image 15. master.display(); 16. 17. //Write the file to a different format 18. master.write(argv[2]); 19. 20. return 0; 21. 22. }
Prog 2.1: Demonstrate the parts of a Magick++ program The Magick++.h file has all the class definition and is included in line #1. Line #4 should be added to differentiate the classes in other namespace from that in Magick namespace. Instead, the programmer can also add Magick:: to each of the Magick++ classes.
Compiling a Magick++ program In this chapter and all subsequent chapters, we assume that the program will be compiled using a *nix machine and using a c++ compiler, although the code was also tested using g++ compiler. To compile your code, ensure that the path to libraries and include files of ImageMagick are included in the *nix PATH. The methods for setting the PATH may vary across different
systems and will not be discussed here. Magick++-config is a shelll script that assists programmers by bringing together the various options needed for compiling. To compile a Magick++ program called first.cpp (given above) and to produce an executable first, use the following command. c++ -o first first.cpp `Magick++-config --cppflags --cxxflags --ldflags --libs` In the above command, Magick++-config script is requested to run with cxxflags – to provide code optimization cppflags – to include header files ldflags – to include library files libs – to include other libraries like jpeg, tiff etc
1. 2. 3. 4.
In this chapter, we looked at the different parts of a typical Magick++ program and also the methods to compile the same. In the next two chapters, we will concentrate on understanding the various classes that form the basis of Magick++.
Chapter 3: Introduction to Magick++ classes In this chapter, we will look at an overview of the various classes available in Magick++. We will list the various classes and a brief description of their function and then a detailed look at how these classes work together in-order to create a good programming practise. Magick++ classes There are a total of 11 classes in Magick++. The major class is Image as it can read, write and create images. Other classes like Color, Geometry etc are used to support the functionalities in Image class and other classes. In the following table, the various classes are arranged roughly in the order of importance. Class Image Drawable Blob Pixels Function Create, Read and Write Images. Also used for manipulating the images Create vector graphics like lines, circles etc Short for “Binary Large OBject container”. In simplistic term, a BLOB is a group of associated pixels identified using a pointer Modify pixel values either individually or in groups. This is one of the most powerful features of Magick++ compared to ImageMagick command line. This feature allows unprecedented access to the pixel data Generate error and warning Define color in the image Define geometry of the image Stitching images Information about the supported image formats Magick++ allows use of STLs using this class and can be used for manipulating images with multiple frames like GIF, Tiff etc Font type metrics
Exceptions Color Geometry Montage CoderInfo STL TypeMetric
Image class is the base class in Magick++. For example, a programmer creates an image using the Image class and then uses the Drawable class for performing vector graphics and writes the file to disk using Image class. The programmer can also read an image using the Image class and manipulate the individual pixels using the Pixel class. The BLOB class is used for specifying images with transparency like JPEG and PNG in combination with Image class for reading and writing images.
Errors in reading, writing, creating or manipulating the images can be obtained using the Exceptions class. Magick++ provides a dictionary of terms that can help in debugging the application. The Exception class need not be restricted to every line of code but can be nested across multiple lines for better programming clarity. The Color class is used to define the color specification in an image like RGB1, Grayscale, YUV2 image etc. The Geometry class provides a convenient and programmer friendly method to define geometry like image size. Good news for pointer-phobics: Magick++ classes are best instantiated as automatic variables (as stack variables) instead of pointers (using new). By using automatic variables, Magick++ keeps tab of bookkeeping and ensures that additional copies of the same image is not created. In this chapter, we looked at the different classes in a Magick++ program and discussed briefly their purpose. In the subsequent chapter, we will discuss few of these classes like Image, Drawable, Exception and Pixel class in more detail with example program.
1 RGB image is defined by three values at each pixel location, the pixel values being red, green and blue 2 YUV image is defined by three values with Y representing brightness and UV representing color. This system is generally used in TV transmission
Chapter 4: Image class – Part 1 In this previous chapter, we looked at the overview of the various classes available in Magick++. In this chapter, we will focus on the Image class, the base class and learn its features and some of it functionalities. We will compliment these with example programs that will aid in the understanding of its use. Image class As indicated earlier, Image class is the main class in Magick++. It can 1. Read and Write almost all common formats including some field domain specific formats like dicom 2. Create new images 3. Perform image filtering1 4. Perform geometric image transformation 5. Improve quality of photographs 6. Perform image modification like slicing, bordering etc 7. Segmentation2 8. Set image attributes 9. and more such features which could not arranged in to this list Image class should be used with other classes like BLOB, STL, Color, Drawable. Image class can read single frame images like JPEG, PNG etc while STL can read multiframe images like TIFF, GIF etc. Image class is included by using the header “#include ”. The command “using namespace Magick;” is specified to ensure that Magick++ functions and classes get called with the appropriate namespace. The programmer can also use “Magick::” before these functions. Image classes are best instantiated automatically (using stack) instead of using pointers (via new). This ensures that Magick++ keeps better bookkeeping and hence lesser memory leaks.
Reading and Writing Images The following program illustrates the use of Magick++ using a simple example. An image file will be read and written back to the disc using a different file name.
1 Filtering refers to a combination of operations like removal of noise, sharpening edges, convolving images to produce blurring etc 2 Segmentation is the process of seperating the contents of an image in to parts by analyzing characteristics of the image like color, texture or based on correlation with real world objects.
1. //Instruction for compiling 2. //Compiling - c++ -o readwrite readwrite.cpp `Magick++-config --cppflags --cxxflags --ldflags -libs` 3. //Executing - readwrite infile.ext outfile.ext 4. 5. 6. #include 7. #include 8. using namespace std; 9. using namespace Magick; 10. 11. int main(int argc,char **argv){ 12. 13. //If all arguments are not supplied, print error 14. if(argc<3){ 15. printf("Usage: readwrite infile.ext outfile.ext\n"); 16. exit(0); 17. } 18. 19. //Create the class and read the file 20. Image master; 21. 22. //Read the inputfile 23. master.read(argv[1]); 24. 25. //Display image 26. master.display(); 27. 28. //Write the file to a different format 29. master.write(argv[2]); 30. 31. return 0; 32. }
Prog1 : Readwrite.cpp : Read and Write image files Line 20 creates an instance of the Image class and will be referred as master. Line 23 reads the file and line 26 displays it. In system not setup for X Windows session, line 26 has to be commented to ensure there is no error. Line 29 outputs the image in to the file name specified in the command prompt.
Add noise to an image In the next program, we will add noise to an image using the addNoise function. This is one of the simplest example of a function that can be called in the Image class.
1. //Instruction for compiling 2. //Compiling - c++ -o addnoise addnoise.cpp `Magick++-config --cppflags --cxxflags --ldflags -libs` 3. //Executing - addnoise inputfilename.ext outputfilename.ext 4. 5. #include 6. #include 7. using namespace std; 8. using namespace Magick; 9.
10. int main(int argc,char **argv){ 11. 12. if(argc<3){ 13. printf("Usage: addnoise inputfilename.ext outputfilename.ext\n"); 14. exit(0); 15. } 16. 17. //Create the class and read the file 18. Image master(argv[1]); 19. 20. //Add Poisson Noise. This can be any other noise type as well. Refer full documentation 21. master.addNoise(ImpulseNoise); 22. 23. //Write the file to a different format 24. master.write(argv[2]); 25. 26. master.display(); 27. 28. return 0; 29. }
Prog2: addnoise.cpp: Adding impulse noise (also called Salt and Pepper noise) to an image Line 21 is used to add impulse noise in the image. There are other types of noise available as constants defined in Magick++. For full details, refer the documentationT3. The image below illustrates the effect of adding impulse noise to the image. The left image is the original image and the right image is the noisy image, characterized by its salt and pepper style of noise.
(Left) Original image before adding impulse noise (Right) Image after adding impulse noise. Note the characteristic salt and pepper formation in the image.
Removing noise from image The program below is used to remove the impulse noise that was added in the previous image. A median filter is used to remove the impulse noise. So in this program, we will use the median filter on the noisy image created using program 2.
3 The website for viewing complete documentation - http://www.imagemagick.org/Magick++/Documentation.html
1. //Instruction for compiling 2. //Compiling - c++ -o removenoise removevoise.cpp `Magick++-config --cppflags --cxxflags -ldflags --libs` 3. //Executing - removenoise infile.ext outfile.ext 4. 5. #include 6. #include 7. using namespace std; 8. using namespace Magick; 9. 10. int main(int argc,char **argv){ 11. 12. if(argc<3){ 13. printf("Usage: removenoise inputfilename.ext outputfilename.ext\n"); 14. exit(0); 15. } 16. 17. //Create the class and read the file 18. Image master(argv[1]); 19. 20. ///Remove ImpulseNoise using median filter. The input to the function is the radius of the circular neighborhood considered for median filter 21. master.medianFilter(1.0); 22. 23. //Write the file to a different format 24. master.write(argv[2]); 25. 26. master.display(); 27. 28. return 0; 29. }
Prog3: removenoise.cpp: Removing impulse noise added in the previous program Line 21 uses the medianFilter function to remove the impulse noise. The imput to the function is the radius of the neighborhood in which the median filter is applied. Higher values will result in more blurring of the filtered image.
(Left) Original image before removing impulse noise (Right) Image after removing impulse noise. The median filter also resulted in some blurring in the image.
In this chapter, we looked at the different features of the Image class and worked in detail to read, write and filter images. Image class provides many more functions to perform complex operations on the image. Some of these functions require the use of primary classes like Drawables, Blob etc and also secondary classes like Color, TypeMetric etc. Please refer to the documentation for more details. In one of the subsequent chapter, we will discuss the other important image processing function, segmentation and will provide a few examples for illustration. But before we proceed with more details of the Image class, we will work on the Exception class, in-order to provide a method to identify errors in our program at run time.
Chapter 5: Exception class
In this chapter, we will focus on the Exception class, to identify errors in the Magick++ function calls at run time, ensuring easier debugging of code. We will compliment it with example program that will aid in the understanding of its use.
Introduction The Exception class is derived from C++ exception class. It is called using try/catch block. The exception in Magick++ can be 1. Warnings, which allows programs to continue its running but could result in erroneous output or 2. Errors, which will terminate the program. Some errors like file read error can be fixed with user intervention.
The try/catch block can be placed across single Magick++ function call or across a block of code. Here is an example that illustrates the use of try/catch to determine whether the read operation was performed successfully.
1. //Instruction for compiling 2. //Compiling - c++ -o try_catch try_catch.cpp `Magick++-config --cppflags --cxxflags --ldflags --libs` 3. //Executing - try_catch infile.ext outfile.ext 4. 5. #include 6. #include 7. using namespace std; 8. using namespace Magick; 9. 10. int main(int argc,char **argv){ 11. 12. //If all arguments are not supplied, print error 13. if(argc<3){ 14. printf("Usage: try_catch infile.ext outfile.ext\n"); 15. exit(0); 16. } 17. 18. //Create the class and read the file 19. Image master; 20. 21. //Read the inputfile. If the file does not exist, throw an exception and quit 22. try{ 23. master.read(argv[1]);
24. } 25. catch(ErrorFileOpen &error){ 26. cerr << "Error: " << error.what() << endl; 27. } 28. 29. //Display image. If the display system does not work, throw an exception 30. try{ 31. master.display(); 32. } 33. catch(Error &error){ 34. cerr << "Error: " << error.what() << endl; 35. } 36. 37. //Write the file to a different format 38. //If there is any error in writing the file, throw an exception 39. try{ 40. master.write(argv[2]); 41. } 42. catch(Error &error){ 43. cerr << "Error: " << error.what() << endl; 44. } 45. return 0; 46. }
Prog4: try_catch.cpp: This program checks for error in reading and writing a file.
The first try/catch block (Lines 22-27) is placed across the read function to determine any error in reading such as missing file. The second try/catch block (Lines 30-35) is placed against the display function to determine any error in the Xwindow system rendering. The third try/catch block (Lines 39-44) is placed against the write command to report error in writing file due to insufficient space, permissions etc. These try/catch blocks can also be combined to reduce the amount of code in the program and the level of sophistication of the program. With this background, we will look at all other classes in the subsequent chapter. Due to constrains in having large programs inside the text of this tutorial, we will not be performing error and warning checks in some of the subsequent programs. But for good programming practice, exception have to be thrown and checked. In the next chapter, we will focus on performing segmentation using Magick++ using Adaptive thresholding and Fuzzy C Means clustering algorithm. Each of these algorithms will be briefly introduced and the corresponding programs will be discussed.
Chapter 6: Image class – Part 2
In chapter 4, we looked at the overview of the Image class and discussed a few functions, for filtering images, in detail using some example program. In this chapter, we will discuss a higher order image processing function like segmentation. We will first demonstrate a program for performing adaptive thresholding and then a program for performing fuzzy c mean clustering. Each of these algorithms will be explained and then the program will be illustrated to ensure complete understanding.
Segmentation Segmentation is the process of separating the contents of an image in to parts by analyzing characteristics of the image like color, texture or based on correlation with real world objects as the first step in understanding the content of an image. There are multiple techniques for performing segmentation like thresholding, clustering, watershed segmentation etc. ImageMagick and Magick++ provides functionalities to perform adaptive thresholding and fuzzy c mean clustering.
Adaptive thresholding In a typical thresholding, the property that the background has a uniform intensity is used in determining the the difference between foreground and background. But in real world image, the background may not be uniform and hence a more sophisticated approach that takes in to account the change in background with location in the image is required. Adaptive thresholding studies the background in a region smaller than the size of the image and determines the threshold that separates the background from the foreground for that region. 1. //Instruction for compiling 2. //Compiling - c++ -o adaptivethreshold adaptivethreshold.cpp `Magick++-config --cppflags -cxxflags –ldflags -libs` 3. //Executing – adaptivethreshold inputfilename.ext outputfilename.ext 4. #include 5. #include 6. #include 7. 8. using namespace std; 9. using namespace Magick; 10. 11. int main(int argc,char **argv){ 12.
if(strcmp(argv[1],argv[2])==0){ printf("You are trying to overwrite the file. But I stopped it.\nTry again with a different output file name\n"); 46. exit(0); 47. } 48. else{ 49. image.write(argv[2]); 50. } 51. } 52. catch( Exception &error_ ){ 53. cout << "Caught exception: " << error_.what() << endl; 54. return 1; 55. } 56. return 0; 57. } Prog 5 : adaptivethreshold.cpp : Perform adaptivethresholding on an image
13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45.
int width,height,intensity_offset; if(argc<3){ printf("Usage: adaptivethreshold infile.ext outfile.ext width height intensity_offset"); exit(0); } //Construct the image object. Seperating image construction from the // the read operation ensures that a failure to read the image file // doesn't render the image object useless. Image image; try { // Read a file into image object image.read(argv[1]); //If width is not specified, assume the smaller region is same as the full image if(argc<3){ width = image.columns(); height = image.rows(); intensity_offset = 0; } else{ width = atoi(argv[3]); height = atoi(argv[4]); intensity_offset = atoi(argv[5]); } image.adaptiveThreshold(width,height,intensity_offset); // Write the image to a file
Line 23 creates an instance of the Image class and will be referred as image and Line 27 reads the file. Lines 29-38, sets the width, height and offset depending on either the user input or to the default values of image height, width and offset of zero (0). Line 40 performs adaptive thresholding. Line 44-51 outputs the image in to the file name specified in the command prompt with an error check to prevent file overwriting.
The program can be run with the following input. The width and the height of the region is chosen as 100 and 100 pixels respectively. The offset is chosen as 30 gray scale values.
adaptivethreshold scan.jpg adaptivethresh.jpg 100 100 30 The input given above results in segmentation as shown in figure below. The left image is the original image before thresholding. It contains two objects VGA adaptor and a marker. The background intensity is lighter in the top region compared to the bottom. Hence a single threshold cannot be used to segment the two objects from their background and hence adaptive thresholding is an ideal technique in such cases.
(Left) Original image before thresholding (Right) Image after thresholding. Note that the different background under the two objects have been segmented and identified as a single background.
The width and height of the region is chosen depending on the expanse of the background
region. If the background region varies considerably across the image, a smaller width and height has to be chosen. Since in this example, the variation is less frequent, a larger region size was chosen.
Fuzzy C Mean Clustering The adaptive thresholding technique separates the foreground from the background. It gives an intensity of 1 for all foreground pixels and 0 for all background pixels. What if you need to classify the regions in to finer elements like identifying pixels in the left image in previous figure belong to VGA adaptor and pixels belonging to the marker and its cap. For such detailed analysis, a fuzzy c mean clustering technique is an ideal choice for segmentation. This method works by classifying the different pixels in the image as belonging to on e of the many possible clusters. The clusters share a common property that their intensities are similar. This process of clustering is repeated till all possible clusters are identified. The following program can be used to perform the clustering.
1. //Instruction for compiling 2. //Compiling - c++ -o segment_fuzzyc segment_fuzzyc.cpp `Magick++-config --cppflags -cxxflags –ldflags -libs` 3. //Executing – segment_fuzzyc inputfilename.ext outputfilename.ext 4. #include 5. #include 6. using namespace std; 7. using namespace Magick; 8. //g++ -o segment segment_fuzzyc.cpp `Magick++-config --cppflags --cxxflags --ldflags --libs` 9. //segment infile.ext outfile.ext cluster_threshold smoothing_threshold 10. int main(int argc,char **argv){ 11. 12. double cluster_threshold,smoothing_threshold; 13. 14. if(argc<3){ 15. printf("Usage: segment infile.ext outfile.ext cluster_threshold smoothing_threshold"); 16. exit(0); 17. } 18. 19. if(argc<4){ 20. cluster_threshold = 1.0; 21. smoothing_threshold = 1.5; 22. } 23. else if(argc<5){
24. cluster_threshold = atof(argv[3]); 25. smoothing_threshold = 1.5; 26. } 27. else{ 28. cluster_threshold = atof(argv[3]); 29. smoothing_threshold = atof(argv[4]); 30. } 31. 32. Image image; 33. 34. try { 35. //Read a file into image object 36. image.read(argv[1]); 37. 38. image.segment(cluster_threshold,smoothing_threshold); 39. 40. //Write the image to a file 41. image.write(argv[2]); 42. } 43. catch( Exception &error_ ){ 44. cout << "Caught exception: " << error_.what() << endl; 45. return 1; 46. } 47. return 0; 48. } Prog2: segment_fuzzyc.cpp: Performing Fuzzy C Mean clustering to an image To run the program, use the following command,
segment_fuzzyc scan.jpg segment_fuzzyc.jpg 2.0 3.0 Line 19-30 sets the parameters for fuzzy c mean clustering. If all the values are not provided in the command line, a default value of 1.0 and 1.5 are assumed for the cluster threshold and the smoothing threshold. Line 38 performs the fuzzy c mean clustering using the segment function. The image below illustrates the effect of performing fuzzy c mean clustering to an image. The left image is the original image and the right image is the fuzzy c mean clustered image. The clustered image has multiple regions corresponding to the VGA adaptor, marker body, marker cap and their respective backgrounds.
(Left) Original image before segmentation (Right) Image after C Mean clustering. The clustering operation has produced multiple regions that have homogeneous characteristics.
In this chapter, we discussed the one of the important image processing function, segmentation and illustrated it with a few examples. In the next chapter, we will look at drawable class and study methods to create vector graphics like line, circle etc and also print text which would later be used in advanced tutorials in creating captchas.