 I noticed that there is a lot of confusion in people's mind as to what exactly to do in this project. The project is necessarily an open-ended project and the activities that need to be done are not defined again by design. This is exactly what happens in real world when you start writing programs for solving a problem. The problem is ill-defined and defining a problem constitutes a major amount of work for a programmer. You are expected to actually discuss, design and take decisions. However, when it comes to handling images, it is apparent that since you are not specialist in image processing, you are struggling to find out what to do with these fingerprint images, how exactly they could be compared. I am going to discuss some additional features of programming, particularly files and strings and in the process I will also discuss how to read those XPM files. To begin with, I will very briefly describe the notion of functions again. The program which I have written for discussion today has not been divided into functions but as a precursor to a good design, I will describe how exactly any programming system should be necessarily broken into functions. Later we shall see the handling of the image array more specifically converting grayscale images into monotone images so that you can actually process them. You can find out ridges, you can find out continuous lines, discontinuous lines, etc. So that that will help you in your project. However, just to recap, when you describe data in your programs, depending upon at which place you have described the data, the variables that you define, the arrays that you define, the files that you define are known within a certain segment of the program. That segment is known as scope. For example, if you describe a variable say i as int i within a for loop, you can say for int i equal to 0, semicolon i less than equal to something, something, etc. In which case i exists and is known only within that for loop, not outside it. You might have used the variable i to mean something else outside which is perfectly permitted. This kind of scoping permits you to use the same variable in different sense, not necessarily a good practice always, but it is important to know how C++ scopes the variables. Here is a simple example. For example, if I define an integer a character as a variable care, a string 20 character array, unsigned int number of sons, for example, then these variables which are declared before int main are known as global variables. They are globally known, they are not known only within this program, but if this program compiles something else, then they will be known exactly throughout this program without any problem. What you define inside int main, these are local variables. What is the difference between the global and local variables? Well, if you have some function definitions, then those function definitions will also inherit these global variable definitions unless they are redefined. So the advantage is that if you have global variables, they are known throughout your program code. On the other hand, what you define here inside are known as local variables. So local and global variables are an important distinction that C++ makes in scoping the variables. There are many detailed rules about scope and I expect you to familiarize yourself with those detailed scope rules. They are available on the website as well, a reference that I am going to give here. You can read that reference, even Kohur's book gives you enough information about scoping. We have seen how we can write functions and how we can call functions. This is just to recapitulate that ordinarily the parameters can be passed by a value to the functions. So when I say invoke a function, say average or something, and supply let's say three parameters a, b and c, then those three values go to the function. However, if any one of these values is modified within the function, that modification is not reflected back. This is known as passing the parameter by value. The only value which comes back is the value which is returned by the function. So notice if I say integer function something or care function something or float function something, then that care integer or float defines the returning value. So when I say in my own int main return zero or return one or return minus one, those are the integer values which are returned back because the main function is often defined as int main. Of course, if you do not expect any function to return any value, you can define the function as void something in which case there is no notion of any value being returned. So function then is a module which just carries out a prescribed task and comes back to you. For carrying out that task, if it requires certain values, those values are typically passed by value here by mentioning those parameters as name. However, if you want the reflected, if you want the changed value within the function to be reflected back in the calling program, you can pass the parameters by reference. So a reference to the parameter address is passed so that any change that occurs within the function for such parameters is always reflected back into the original parameter. Obviously, a constant value sent to a function cannot be a passing by reference. It is always passing by value. But if you have variables, then the variable addresses can be passed which is called passing by reference. Please note that arrays are always passed by reference. Here you mention an array name, the pointer to that array is passed. Now functions are ordinarily written at the beginning, but these can also be written later if you provide a prototype at the beginning. So what is a prototype? Prototype is merely the way you would invoke the function in your program. So you will write the name of the type for int, float, void, whatever name of the function and in parenthesis, you can simply write the types of arguments which are passed on. So some arguments could be integers, some could be car, star, pointers, some could be something else just the types. What is the purpose of doing this? Ordinarily when your program is compiled, since the functions are written at the beginning before int meant, the compiler knows not only what each function is going to do, but how exactly the function will be called because the first line of the function describes how it will be invoked. That way in the main program whenever there is a reference to a function, it can resolve, it can compile the calling appropriately because it knows how to reserve space on what is known as a stack which is used as a mechanism to contain information that is passed on from one unit of program to another unit of program. If these functions are not defined at the beginning, compiler would get confused about such passing mechanism. Ordinarily however, you would like to write functions maybe at the end, in fact, you may want to write the functions completely independently somewhere else. To permit that to happen, function prototypes can be defined along with your main program. So for example, this is a name of a function called proto function. It is not a special name, it is the name of the function itself. So int proto function in bracket int first comma int second. If you just write this line, the word proto is only notional here by the way. You will write the actual function name here by which you are going to call that function. No body of the function need to be written here. In fact, you can simply write int function int comma int. What is the purpose? It is to tell the compiler that whenever this function is called, the first parameter will be integer, second parameter will be integer. Although writing some name as first and second makes it more meaningful, but it is not required. All the purpose that is served by this prototyping is to tell the compiler how exactly this function will be invoked. Once that is known, the main program is compiled properly. Of course along with it, the functions would be compiled if they are written at the end of main program. So please note that proto of a function is exactly identical to the function definition except that it does not include the body of the function itself. What is the advantage of doing this? First such prototypes need not actually be written physically in the same program file. They could be written in a separate file. Just a file of prototypes, 1, 2, 3, 4, 5, your 20 functions. You write 20 prototype and include that entire file which by convention is called a .h5. For example, you have written these 20 functions, full body is there, they are very complex functions, but they have been written separately and they have been compiled separately. It is possible to compile a separate function independently. Now this compiled function could go into a library in an object form. So obviously there is no question of including the source code of these functions in your main program. In fact, the source code may not exist. Somebody else might have written these functions. So they will exist as a form of compiled library somewhere. But your main program when you write, your compiler must be able to determine how exactly these functions will be called. And that is why you will include prototypes of these functions in a typical file such as image lab notation. Similar for this project, you have written some five or six different functions. Say converting, say reading a .xpm file, writing a .xpm file or converting a grayscale image into a monotone image. All these functions you have written separately and you have compiled them. How exactly these functions will be called could be defined in a prototype set file and that prototype could be image lab .h. Here in your program, you can simply say include image lab .h. When you do that, at the compile time, all the prototype definitions will actually get included when your program is compiled. Now you will understand why you have so many include statements at the top. As a matter of fact, when you say include IO stream, include math, include C string, what you are actually doing is you are asking the compiler to include those header files which contain prototypes of a large number of functions which have been pre-written and have been compiled into a separate library. Once the compiler does the job, of course, while linking, your translated program must be linked with appropriate library functions which have been already compiled. So putting a prototype set into a .h file permits you to define a simple interface to a library of function that we may create. One great advantage of this is that as long as I keep the interface same but change the internal code of that function, I do not have to change anything in my main program. Consider for example a function written to salt an array. Now there are five different ways in which you can apply a sorting process. So there are well-known sort algorithms such as insertion sort, selection sort, bubble sort, etc., etc. You might use one of the sorts and write a function today. Once you define an interface however, as long as you retain that interface, you can completely change the implementation of that function by writing a different sorting algorithm. So this permits you to make your program modular and a program function may undergo changes without affecting the rest of the program. In this particular case, when you have to do a project where somebody has to send let us say an image file to find out whether a duplicate exists or not. Now ordinarily unless some other team writes a function to determine whether a duplicate exists or not, apparently I cannot proceed with my program. To avoid that I can call a function, we say check duplicate. So here is what I can do. So I might write a function which will check for duplicate. I will send one image, star image will mean a pointer to an image and I will send some ID with which I have captured that image. I want to check whether that image already exists somewhere in the database or not. As I said, unless some other team writes this function, I will not be able to check the logic of my program. Now what I can do with this facility that this function need not be written in my program, this function can be written somewhere else. I can write a simple function which is called a stub. Your stub may be int, doop, check, whatever, whatever and I can simply say return 0. This is known as a stub. I have not written anything to check the duplicate. But I know that either it will be duplicate yes or it will be duplicate no and I can decide a priory with the team which is going to write this function that if you find a duplicate return 0, if you don't find a duplicate return 1 or whatever. Now artificially I can write a function in which I do not do anything at all with that image. I simply return either a 0 or a 1 and quickly check how my program executes. So the rest of the program execution now need not depend upon correctness of this function. This function can therefore be written independent. This is one advantage of modularization that when large teams are working together the common functions which are going to be used across teams can be decided upon in so far as the interface is concerned, the voltage files can be defined and anybody who is not writing some functions but requires to use those function can actually write such stubs and proceed with the development. This permits a easy development process where you don't have to wait for anyone. So as I said this prototyping permits a simple interface to a library of functions. The library itself can be kept in a compiled version of object form. There is a very simple explanation by the way I found it on the web. There is a c++.com tutorial website I had given this reference earlier. In fact Johan Soli has written something on the function and function prototyping say reasonably simple explanation you might want to look at that. Now we come back to processing of grayscale images. First of all the grayscale images are difficult to process because they have shades of gray anywhere between 0 to 255. 255 is all white, 0 is all black. But you don't have black and white images. The images which are captured by the device which we demonstrated the other day has various shades of gray. Now in that shade of gray how do you determine whether there is a particular line that you can trace or you can find out consecutive pixels which constitute a line or which terminates a line. You would like to convert this grayscale image into a monotone image. What does the monotone image means? A monotone image is one which has either black or white pixels only. It of course reduces the amount of representation that you require. Technically you require only one bit. 0 would mean black, 1 would mean white. Now since we have values between 0 to 255 technically these are the grayscales which are possible. I can arbitrarily decide that if a pixel value is less than 128 it is black. Otherwise it is white. As we shall see in a moment in actual practice this kind of threshold does not work. What if all the shades that are present in an image are say between 100 to 255? That means if you look at values between 0 to 128 there will be very less value. So you will get lot of white colors instead of getting dark ones. So therefore this threshold has to be decided very carefully. You can increase it to say 180, 170. The ideal value what should be the ideal value? It should depend upon the histogram of the picture. In fact a simplistic threshold definition could be just the average value of pixel. So if the average value of pixel is say 200 then anything less than 200 should be considered to be black. Anything beyond 200 should be considered white. This as we shall see will give us a better picture. Here is a fingerprint image of a person. This is a dot BMP file. You can see that there are shades of gray. So in between the crevice that you see here between the two ridges it is not perfectly white. And therefore there could be a lot of confusion when you apply any function to process this image to find out whether there is a line or there is no line. You would like to convert this into a single monochrome image. Now this is what will happen if you see a monochrome with a value of 128 only. Notice that actually instead of getting the lines clearly you are getting a lot of broken lines here. That is obviously because the threshold 128 does not work correctly for this picture. I have tried to convert this into a monochrome image using a larger threshold say 180. With 180 threshold you can see that you have some semblance of lines. For example this ridge is this minutiae is obvious here. There is a bifurcation here. There is a ridge which goes here and suddenly terminates. You can see this visually but can you see this programmatically? Can you write a program which will determine these points? Where do they exist? What are the angles of the neighbouring lines etc. Still difficult. The best way as I said or rather a better way would be to go by the average of the pixels that are available, pixel values that are available in any grayscale image. So if this is the grayscale image, if I do the averaging, the average pixel value for this particular image was 222. So that means I put the threshold as 222. Anything less than that is black, anything greater than that is white. Then I will get this sharp image. You can notice that in this sharp image I can actually locate ridges and terminal points much easier. Even this is not very simple because the lines are thick. There are large number of ones either across rows or across columns. The subsequent algorithm will be a thinning algorithm where you make the edges thin. How would you thin the edges? If you have large number of ones in a row, you reduce all of those ones by a centre one. Or if there are even number of ones, you reduce that by a single one in between. This is the way you can reduce either zeros or ones appropriately. We shall see that tomorrow when I write the same program in terms of functions to get the thinning and how you could make some comparison. Here is another captured image and this is the mono version with its own threshold being decided by whatever is the average value of the pixel. I had already shown you a program by which you could write the .XPM files. I have now written a program which will read those XPM files into an image array, will convert that image into a monochrome image and will write a monochrome file. Notice that .XPM file first contains a colour palette. We had assumed an artificial colour palette for our .XPM file. For a complete black and white image, there are only two colours, black and white. So the colour palette will have exactly two lines. Further, each colour can be reprinted only by one character. You don't need to spend two characters per colour. Using this simplification, the program that I will have to convert the grayscale image into a monochrome, these are all includes, of course, they are not important. Notice here some of the things. Unsigned char star image and unsigned char star mono image are two images defined. When I will read an .XPM file, I will assemble the image into this image. When I convert it into a monochrome image, I will put it into this mono image. Please remember that when I declare this as unsigned char star, nothing is allocated as an array yet. So there is no image array. What is being declared is only a pointer, a placeholder. So I will have to dynamically allocate memory as much as is required. Notice that last time we could allocate memory because we knew what was the height and width. However, I will not know that unless I read the .XPM file. Because when I read the image through that .XPM file in the first few lines, I will know the height and width. Only after I know the height and width, I will know what should be the dimension of my array. That is the time when the dimension in fact will be decided for these two images. Rest is very simple. I deliberately put V0 and V255 as two extreme values 0 and 255. Obviously these are values meant for monochrome images. I have found out a very different way of calculating the average pixel by finding out the averages across each row and then summing them up and finding out average across all the rows. There is some peculiarity that will be introduced here in processing of strings. Ordinarily when you do input or output, you do it on a file. However, within a file when you read a string, there is a need to extract three or four different values which may be there on one line of a file. In the .XPM file, you will notice that there is one line which contains the width, the height, the number of colors in that image file and the number of characters per pixel that are used. Now these are numerical values. You need to extract them separately. There is a very simple way available because strings are objects in C++. You can actually convert a string as if it were a file. So it is called a string stream. Once you convert a string into a string stream, just like you say C++ or less less something, similarly you can put this string as if it is a file and do input from that string. So this file line string is declared as a string. The purpose is that I will read a string from a file and treat this itself as a file. We shall see the example here in this program. There are just comments to indicate that the files are assumed to be in .XPM format. Again I have not written it but they are assumed to have a color coding which we have explicitly used. That means ordinarily I will have to maintain an array of color codes describing these two characters means this color, these two characters means this color, etc. Since we have a simple numerical formula to calculate that, I have avoided this. Otherwise you will have to assemble the color code array from the first few lines of the file and then use that to decode the image pixels. So here I get a file name for input fingerprint image. Please note that file name S is a string which I just pick it up. I define an input file stream image in file 1 and then I construct a name which is file names plus .XPM and then I open that file. Please note that when I construct a name in the string of object type C++ I must convert it into a C string type we had seen this last time. This is the only time when a string is not permitted as a parameter you have to use the character array type parameter for this function. The reading is very simple. I am skipping the first three lines because the first three lines of .XPM file that we had written contains first a comment .XPM. So those three lines are not really relevant. Now I have to read height, width, number of pixels from the next line. So I actually get line in file line string. This is a string in which I have these four values. Ordinarily I will have to do a lot of mara mara to extract these four values by looking where this value is, where this value begins. Some of you will recall how you had extracted the marks for the mid-same, end-same, etc. if they are given in a line. A much easier way however is to first find out the length of this string. If length is n you know that the way the lines are written in the .XPM file you have an opening double quote followed by the values with spaces and a closing double quote and a question and a comma. This is important to remember this. This is how a line will look like. So when you get the line in the lines, this string, file line string will actually contain this and the total length n will be returned by this function call which is actually a method for the object called file line string.length will get you the length. Now what I am doing is I am defining a new string which is called input 1. This input 1 I have defined it as a string but the way it is being defined is that it is being defined as a string stream. Stream means a file. So usually I have an IO file input file output file. What I am going to do is I am going to treat this string as a file. Once I treat this string as a file I can perform input operations as if this name itself was a file name and the way I handle it is I take the appropriate substring which is 1 comma n minus 2. Notice that if n is the length of the string then I must not begin with 0 because the first character is a double quote. I ignore that. Then n minus 2 will remove the last double quote n comma. Consequently we go back to this point I shall have this string left inside the string. This substring method is a very powerful method by which you can actually take out a portion of a string starting at some point and having so many characters. The second parameter defines the number of characters in that substring. If you omit that it means up to n. So these are extremely flexible mechanisms available on the string objects. Notice that actually if I were to feed input on a file that is on a terminal if I had a C in statement and if I were to give 4 values this is exactly how I will give those 4 values. 200 blank, 129 blank, 256 blank, 2 and end of line. That is how I will give the input. So I create a string exactly like this by writing this substring 1 comma n minus 2 on the file line string and this entire resulting line I declare as input 1 which is not an ordinary string anymore. The moment I put this I string stream then that means this input 1 becomes a file. Consequently I can actually write a statement in C plus plus like this. Input 1 greater greater n width, greater greater n height, greater greater n colors, greater greater num care percent. So I will automatically get these 4 values in the 4 variables. This is by far the easiest way of getting something very complex written on a single string as different values and extracting those values independently. Of course this task can be done in variety of different ways. I just wanted to introduce this particular way. It is at this stage that I know the width and height. So far I did not know. That is how I can now declare an array of the requisite site for both my grayscale image as well as monochrome image. Image is equal to new unsigned care n width star n height declares that array. So this new statement is important statement. It actually grabs memory dynamically from the operating system and allocates that memory to the array called image. Similarly I create an array for mono image as well. Notice that there is no difference in the space that is occupied by both these images. Although mono image has only 0 or 1, I propose to store 0 or 1 in 1 byte per pixel. So there is no difference in the storage, but the values become simplified. The reading of the .xpm file is very straight forward. I will keep that .xpm file in front of me. It's a text file. So I can keep reading lines now. I have to skip all the lines which define the character code. So I will skip one comment line and next n colors line. So for i equal to 0, i less than equal to n colors. I will just get line and forget that those lines. Now I read the image pixel values. Notice how I will read the image pixel values. I get line, I get the length of the line and now again put that line into a string called input 1. So now input 1 can be treated as a file. Once I have a file, I can use the input operations. Since each line has n width into 2 characters surrounded by double code and a comma. This is exactly how a color line looks like. All that I need to do is I have to forget the first opening double code. Then I have to collect 2 characters each per pixel, convert them into a picture value and put it in the proper position in the array and finally forget the last double code and comma. I can do that if I treat this entire thing as a string which is how it is shown here. Notice that when I say i string stream input 1, this substring starting from 1 up to end of whatever string I had. So whatever line I had read would have had the double code followed by characters, characters, characters, double code and comma. If I don't start with 0, if I start with 1, that means the first position will be here. Notice that in an array the first position is 0th position. So I have already got rid of this double code. That means this substring actually denotes the portion from this point right up to the end. 1 comma nothing, just 1, that means 1 to end. So I now got a string from which I can keep reading characters one at a time. So for j equal to 0 to j less than n width, I calculate the position and notice how I simply read character 1 and character 2. For each column I had to read two characters. As many columns as I have, those many into two characters I would have read. And I need not do anything with the remaining semicolon, with the remaining double code and a comma at all. I can just simply forget them. Notice how I convert the value. You will recall the way I had designed the color palette. That means if I subtract a from character 1 and multiply it by 25 and subtract smaller from character 2 and add the resultant here, that simply gives me the value of the picture. Because I had translated a value that was obtained from the image scanning device into these characters in exactly the opposite way. So once I have the value, the position is determined by i and j. I simply convert that value into unsigned care which is the type. Unsigned care and unsigned int are interchangeable. I will put that value into image pass. At the end of this double loop, there is a loop for i earlier. I would have extracted the image from the .xpm file into the array called image. So reading that .xpm file is very simple. Please remember that if I had a complex color palette in which I had not used a very simplified scheme of assigning colors. For example, if I had 100 colors and there were odd colors, then I will have to indeed collect all the character codes for those colors, that is in the color palette, put them in an array and every character I read, the combination of CH1 and CH2, I will have to search in that symbol array to find out what is the corresponding color. And that color value I will have to assign. This simplification helps me to reduce programming effort here. As I told you, I want to convert this into a monochrome, but before converting it, I want to calculate a threshold. So I calculate the average pixel value. The average can be calculated by summing up all the pixels and dividing it by a single number n-width multiplied by n-height. In general, however, n-width and n-height could be very large numbers themselves. Since each pixel in its own right could be 0 to 255, when I add up such very large number of pixels, the sum may well go beyond the bounds of n-t. Today we are accustomed to writing programs for images which are say 300 by 500 etc. But imagine an image which has been captured by a satellite. That image could very well be in the form of say 20,000 pixels by 20,000 pixels. Now obviously finding out averages is not going to be very straightforward there. So here is a simple squiggle. What I do is, for every row i equal to 1 to n-height, for 0 to n-height, for every row, I calculate the sum of all columns in that row. So I start with sum called as 0 and all the position i, j, I find out the value and I simply add it to sum of the columns. At the end, I calculate the average of all the pixels found in that row by dividing the sum by the end width. So I now have an average value for that row. You will agree that if I calculate such averages for every row and add up all the averages and then finally divide them by n-height, I will still get the same average. The advantage is that individually the sum called and the average sum row is likely to be within the limits of long end, independent of the size of the image and that is how this small trick will help me get the value correctly. At the end, I will get the average value. Having obtained the average value, I simply have to write it out, not the average value but I have to write out a monochrome file. So here is a variation of that previous program which does not write a complex color code followed by all kinds of characters depending upon different values in pixel. But now it will convert every value into 0 or 1 and write it into a simply two color map. So what we do is we convert the image into a monotone, value less than average is set to 0, greater than average is set to 255. And this makes it very simple. First of all, I calculate the value if it is less than equal to average, I say mono image pass is unsigned care v0, else mono image pass is unsigned care v255. The entire image now has been converted into an image with value either 0 or 255. So this is what is known as converting from gray scale to monotone. It still will have lots of ones. As I said, we shall examine this later tomorrow. But having got this array now, having got this image array, I have to write a much simpler version in monochrome. What I do is I simply add a letter M before whatever file name I had that will qualify the file as monochrome file. In your programs that you write, please remember to spend considerable time in deciding what should be the names of your files. Because you are going to deal with thousands of files. In real life, the UID project will have to deal with exactly 100, sorry, 1,000 million files. And not just 1,000 million, if every person has 10 fingerprints, then 1,000 million multiplied by 10. So you will go absolutely crazy if the file names are arbitrary. And therefore some standardization on the file names is very much desirable. One simple standardization is whatever is the name of the file for gray scale image, I prefix M and that becomes a monochrome image. It will be easier to relate one file to a corresponding gray scale file. Anyway, I open the output file and if the file is open, I do this simple thing. The first three lines are written blindly, which has a command xpm, then static care, star, file name followed by width, height, end colors. These are the three lines. Now, after writing these three lines, I am actually writing end width, end height. Notice that the number of colors I have is only two and number of characters per color I have is only one. Now, I write the color palette header, which is just colors. The color palette itself has only two lines. So you say x for black and dot for white. Arbitrary choice, it could be A or B as well. All that I say is image out file x blank C color 0000 closing quotation and dot is FFF. Just these two color codes are sufficient because I am going to use either this code x or dot. It could be A, B, whatever. It doesn't matter which characters you choose. Once I have chosen these characters, however, I have to insert the pixel code lines and the pixel code lines are written in the next segment. So for each picture row, I compose the remainder of the line. The line starts with a double code and then for every column 0 to n where I have to insert one character and that character has to be either x or has to be dot. So notice how simply it is done. I find out the position. I find out the value at that position and if the value is 0, I set the character to x otherwise I set the character to dot and I simply write that character to image out file 1. When I repeat it for all the columns, I would have completed one line. At the end of it, of course, I have to write the quotation mark and a comma which I have written here. Once I do that for all the lines, my file is over and that is how I will get that dot.xpm file. Incidentally, dot.xpm files cannot be seen because many of the utilities do not work on dot.xpm files. As I told you the package which is the imaging package, if you install it, you can see that. Otherwise you can convert these into dot.bmp files. This is simple. By the way, these delete statements are important. At the end of your program, the memory which you have dynamically allocated should be released back to the operating system. There are many instances where programs do not do this and at the end the operating system suddenly falls short of memory because all its memory has been hogged by programs which are actually executed and disappeared from the computer. So this is an important thing that you have to remember to do. Okay. I have got lots of emails saying when I say you should send an email, how exactly do I send an email? Or there are questions like do we necessarily store the images in dot.xpm format only? Now these questions are being asked because all of you are used to answering questions which are very specific. This time the question is do this project. Since the question is not asked correctly you find yourself unable to answer that question. The point that I am trying to make is whenever what is to be done is not well defined that teamwork will mean skewed efforts. Some of you will have to spend a whole lot of your intellectual capital on thinking, discussing and deciding. Once the decision is made the entire team can then write programs according to that desire. This is necessarily open-ended. It is so by design. It is not by default. There will not be any further great explanation on how the project is to be done. If you are unable to figure out something whatever you feel you can do you should go ahead and do it. Please understand that nobody expects in this world that a team of first year students will actually solve a complex image analysis problem to handle fingerprints. But what is expected is that you take decisions and whatever you can do you should do within the realm of those project activities that have been defined. So learn to take decisions, learn to discuss design and document. Spend time on deciding naming conventions. Spend time on deciding file structure, memory data structure, identify functions and write stops. That is the only advice I can give you at this juncture. My last slide says that do not forget that you will have to do peer review to allocate 10 marks for every member of your team of 20-22 people. This has never been attempted by any one of you earlier. At least I do not think so. But in postgraduate courses I have always been doing it. As I have said earlier, I find that given an opportunity you will be able to learn professional self-evaluation and professional peer evaluation. You have to award marks out of 10. I will give a slightly more detail right up on how you may proceed on this. I have decided to add more incentive marking scheme which I will announce tomorrow. These will be for special extra work for best creativity and for best teamwork. These marks will be over and about 25 marks which are allocated to the project. So it is possible that certain individuals or certain teams will get extra credit. But that will be relative grading. I will judge how much is the creativity and how much is the best teamwork compared to other best teamwork etc. Thank you.