|
|
4. Concepts and Basic ProgramsAt present, the documents that are available for understanding libdc1394 are very few. Among the available documents are a FAQ, which only talks about the general concept of the camera and a few forums where people have posted their queries. We had to read the libdc1394 source code to understand how to grab a frame from the camera. The extreme need for a complete explanation on this topic encouraged us to write this HOWTO. On the basis of what we understood by exploring the source code of the camera, we are presenting our insights on the library. We encourage you to keep referring following files while reading through the next section:
The dc1394_control.h file is the most important, as it contains the declaration of various functions and data structures. It should be read to understand the features supported by IEEE1394 cameras and the functions which access and control various features of camera. The dc1394 library works closely with raw1394 since all the functions make use of functions of raw1394 (raw1394_read() and raw1394_write()) in order to retrieve or modify the values of various parameters of the camera. This is one of the reasons why raw1394 must be installed before installing libdc1394. To understand how the functions provided by the library work, we need to understand few technical aspects of the IEEE1394 camera:
With the above background, we begin our discussion about the various functions, data structures and other miscellaneous features available in the dc1394_control.h file. We would like to mention one important aspect of the dc1394_control.h file, which is that it lists out the values that can be set for the data speeds, frame rates, camera modes and image formats. All the values are in the form of enumerations to help you write readable code. For example, enumeration for speed indicates that the data speed can be set only as 100, 200, 400, 800, 1600 or 3200. The dc1394_control.h also lists the features (brightness, hue, sharpness, saturation, etc.) supported for your camera. 4.1. Important Data StructuresThe library provides some structures which are useful in storing camera and image related information. They have been declared in the dc1394_control.h file.
We will be largely concerned with the dc1394_cameracapture structure. 4.2. Types of functionsWe have categorized the functions provided by the library into 6 types. (The categorization is purely done on our own for the ease of discussion). Each of these functions has been declared in dc1394_control.h. We suggest you to keep a copy of the file on hand while going through the subsequent section.
4.2.1. Get/Query FunctionsThese functions are used to get the value of various features of the camera, the information about the ISO channel, trigger mode, frame rate, format and mode. The functions contain get or query in their names. For example,
Most of the get functions take a minimum of three parameters:
If we try to trace the flow of the function call, we can understand what actually happens: In case the get function you called is meant to retrieve the value of a camera feature (the value for the parameters listed in feature enumeration), that get function will call another get function (GetFeatureValue), which takes the enumeration value of the feature as input. For example, in the case of gamma value, the function passes 422 as the value (this value can be calculated from the enumeration given in the dc1394_control.h file). Ultimately, the GetCameraControlRegister function, whose task is to get the value from the appropriate control registers, is called. This functions takes the offset value (octlet_t offset), which is the offset from the base register as the input to its call. The function prototype is declared in dc1394_internal.h.
The above will store the final result in the value.
The GetCameraControlRegister function will in turn call dc1394_get_camera_info() to get the address of the base register:
Once the base register and the offset is known, raw1394_read() is called by GetCameraControlRegister to read the actual values. Now the get function (dc1394_get_gamma) uses the value returned by the GetCameraControlRegister to modify the parameter gamma.
In this way, the user obtains the value of the camera parameter he queried for. 4.2.2. Set FunctionsThese functions are used to set the values of various camera features. There is a corresponding set function for almost each get function. You can recognize these functions by searching for set string. For example,
Like the get function, this function needs raw1394handle_t and nodeid_t for camera identification. The other parameter, gamma, is the user-specified value for the gamma parameter. The flow of the function call is quite helpful in understanding what is actually happening. The flow is exactly same as that of the get function. The only difference is this time all the intermediate functions are also set functions, and instead of raw1394_read(), it uses raw1394_write() to write the value of the camera parameter on to the registers. 4.2.3. Print FunctionsThere are three print functions available:
4.2.4. Setup FunctionsAs the name suggests, these functions are used to prepare the camera to start grabbing the images. In order to setup the camera, some parameters must be passed to the function. The number and the type of parameters are specific to the setup function, but essentially three parameters must be passed in all the setup functions: w1394handle_t, nodeid_t and the pointer to the dc1394_cameracapture structure (this is to provide the buffer for grabbed images and keep attributes, like height and width of frame). As mentioned previously, raw1394handle_t and nodeid_t uniquely define the camera, while the pointer to dc1394_cameracapture provides the buffer for the image frame to be grabbed. It also stores information about the width and height of the frame which is useful at the time of image processing. Other parameters that are passed are data speed, frame rate, image format, image mode and ISO channel number. In case the camera uses DMA, the number of DMA buffers and drop frames is to be provided. As we have already mentioned, we will not be discussing the role of the DMA in this text. The various setup functions are:
These setup functions have been defined in dc1394_capture.c. You have a choice while passing the values for the parameters, like data-speed, format, mode, and channel. Instead of providing the value yourself, you may instruct the function to take the value from the camera. This can be done by passing QUERY_FROM_CAMERA in place of the actual value for that function parameter. The basic flow of control is easy to understand: As shown in Figure 3, the Setup function in turn calls various set functions to set the parameter values to the camera registers. In the case of DMA setup, after the set functions have been called the ioctl system call is called to set the DMA buffers. The ioctl system calls will fail if the DMA is not supported by the camera and in such a case you will get the error message: IDEO1394_IOC_LISTEN_CHANNEL ioctl failed The setup functions also allocate memory for the camera _capture buffer:
4.2.5. Format7 FunctionsThese functions are used only if the camera is set for Format7. This format is preferred since this allows the user to define the size of the image to be captured according to his need. By default the size is 1024x768; you can set it to different dimensions, say 960x720. All Format7 functions have format7 in their function names, and the functions have been defined in a separate file, dc1394_format7.c. The setup function for Format7 has a minor difference from the normal setup since it also asks for the size of the frame, while you don't have to pass the format parameter as the setup function, as it is meant only for a particular format, for example Format7. The function call flow remains the same as discussed in the previous section. The Format7 get functions are called query functions. The mechanism is different from the normal get/query functions: they don't call GetCameraControlRegister; instead, they call GetCameraFormat7Register(). The following flowchart will make the differences evident: The Format7 query function will call GetCameraFormat7Register, which is supposed to read the values from the control and status registers of the camera. This function in turn will call the QueryFormat and CSROffset to know the offset for the particular information that has been queried. After getting the offset, raw1394_read is used to actually read the values. The Format7 set functions also follow the same logic with the obvious difference that the reading functions are replaced by writing functions, for example, SetCameraFormat7Register and raw1394_write(). 4.2.6. Release FunctionsThese are the final set of functions identified by us. The basic job of these functions is to release the memory allocated to the capture buffer by the setup routine. This is essential to save the system from memory leaks. These functions are defined in dc1394_capture.c:
This function in turn calls free (camera -> capture_buffer), which frees the memory. Similarly, the release function is available for DMA setup. 4.3. Coriander: A GUI for the libdc1394 libraryCoriander helps in easy handling of the IEEE1394 cameras. It uses the above discussed functions and libraries and provides a GUI for them. The main advantage of Coriander is that it saves time that is normally wasted in camera setup. Also, Coriander shows only those features and attributes that are present on the camera and hence you can judge how useful the camera will be for your application development. The most important feature of Coriander is its ability to display the captured image at run-time. Coriander also allows the user to convert a BGGR image to RGB. We will discuss the meaning of these types of images in detail in later sections. Some files that can be useful in understanding the functionality of Coriander are:
The Coriander homepage contains an excellent user manual which can be useful in case of any difficulty: http://damien.douxchamps.net/ieee1394/coriander/manual.php. Our use of Coriander was limited only to checking that the camera was working properly and confirming the focus was correct. We will give some more usage information for Coriander in later sections. 4.4. Example: How to grab image from the IEEE1394 cameraIn this section we will demonstrate how to write a small program to grab an image from the camera. We have taken the program (grab_gray_image.c) given in the examples in the library tar file. We have removed some lines to increase the readability of the code. We have provided the explanation for this code below. In order to provide you with a clear picture of which section of the code does what, we grouped the code lines together by task below.
We hope that after going through this algorithmic way explanation you can comfortably understand the example code. If we used the Format7 image format, we would have to change only the setup_capture function. Let us look at the setup function:
4.5. How to get color images: Bayer Pattern ConceptsThe image grabbed by the sample code in the previous section is not colored (we have intentionally used the words "not colored," since the image is not gray-scale either). It is actually a Bayer Pattern. We will give an overview of Bayer Patterns and how they are used to get a colored image in this section. Digital cameras use a solid-state device called an image sensor. These fingernail-sized silicon chips contain millions of photosensitive diodes called photosites. When you take a picture with a digital camera, the intensity of light hitting each photo site on the sensor is recorded as a signal. Depending on the camera, either 12 or 14 bits of data are recorded. At 12 bits, the camera can record 4,096 levels of brightness. At 14 bits, the camera can record 16,384 levels of brightness. This is referred to as bit depth. The higher the bit depth, the finer is the detail, the smoother the transition between tones, and the higher the dynamic range (the ability of the camera to hold detail in both highlighted and shadowed areas). But at capture, digital images are grayscale, not color. To record color information, each pixel on the sensor is covered with a red, green, or blue filter, with the colors alternating. A common arrangement of color filters is the Bayer Pattern array that alternates colors, but that also uses twice as many green filters as red and blue. Twice as many green filters are used because our eyes are more sensitive to green. This pattern, or sequence, of filters can vary, but the widely adopted Bayer Pattern, which was invented at Kodak, is a repeating 2x2 arrangement. Each pixel has been made sensitive only to one color (one spectral band). A Typical Bayer Pattern will look like this: The tile or square (pixel) labeled B means this particular tile is sensitive only to Blue light, and so on. The Bayer Patterns may be classified into 4 types, depending on how we have arranged the colors. The naming of the Bayer Pattern is done by taking a 2x2 matrix from the top most corner of the pattern and the colors being read in (0,0),(0,1),(1,0),(1,1) order. So for the above Bayer Pattern, if we take the 2x2 matrix as: The pattern is therefore known as BGGR The other possible patterns are: The image we obtained in the previous example was a Bayer Pattern image also known as a RAW image. This was stored in camera.capture_buffer. In order to view what we have captured we convert this RAW image to .PGM by adding a header (look at the explanation in Section 4.4). In order to get a colored image, the Bayer Pattern image is converted to a RGB image. A RGB image is an enhanced version of the Bayer Pattern image; we try to find the value of the two missing colors at each pixel (remember that each pixel of the sensor is covered by Bayer Pattern filter so we get a single color at any pixel by default). This is done by using different algorithms like Nearest Neighbor, Edge Sense, and so on: where the shaded values are to be calculated by the algorithm. Subscript denotes the tile on the Bayer Pattern to which the value of R, G, and B belongs. Note that the image size will become 3 times the Bayer Pattern. In order to view the RGB image we convert it to a Bit Map, or .BMP image, by adding a bitmap header.To get a clear picture of what's happening, we have provided the following diagram: Let's understand how the RAW to RGB conversion algorithms work. We will look into the Nearest Neighbor algorithm in detail. Other Algorithms are thoroughly explained at the following web link: http://www-ise.stanford.edu/~tingchen/main.htm. Most of these algorithms make use of some kind of interpolations. 4.5.1. Nearest Neighbor AlgorithmIn this interpolation method, each interpolated output pixel is assigned the value of the nearest pixel in the input image. The nearest neighbor can be any one of the upper, lower, left or right pixels. An example will make the logic clear. We try to find the G values for the R, B tiles for a 3x3 block (shown as shaded region. The blank squares either bear R value or B value. We have not shown them just to make the figure easy to understand). Here we assume the left neighboring pixel value is used to fill the missing ones. The table on the left shows the G values for the Bayer Pattern image. In order to find out the missing G values for the other squares that originally contains only R or B we use the following approach: Find the nearest G value square and copy the G value of that square onto the R (B) square. This has been illustrated in the above figure. The square next to G7 had a value of either R or B. So to get G8 (a G value for square 8) we copied the G value of square 7, since it was the nearest so G8 = G7. Similarly we filled the other non G value squares. The same logic is applied when finding R and B values for the green squares. 4.5.2. Example program to understand how the colored image is grabbed using IEEE1394 CameraNow that we have presented the basic concept of the RAW, RGB and the conversion algorithm, we feel that you can understand an example program that gives us a colored image. We have chosen the format as Format7 because the camera we used responds to this format only. We will make use of another example code which provides the implementation of the algorithms. The program is conversions.cpp, in the grabdma folder, available for download at http://www.ptgrey.com/support/kb/data/grabdma.tgz. To run the code, make sure that you have the following files:
As we have already discussed the use of GetCameraControlRegister, you can understand that it has been used to find out the value contained at 0x1040. Libdc1394 does not provide any function to query this address, so we explicitly used this call to get the value. It is important to understand the utility of the above function call. Refer to our discussion about the Bayer Pattern filters in the previous section. We know that the pattern can be BGGR, RGGB, GRBG, and GRBG. The algorithm that we use for converting the Bayer Pattern to RGB requires to know about the type of pattern the camera filter has got so that it can carry out some initialization (refer to conversions.cpp for details). The fourth parameter in the function call:
refers to this value. BayerNearestNeighbor is the function call for the interpolation algorithm we discussed in the last section. This is implemented in conversions.cpp. Having understood this, we move on to the switch-cases. The value that is obtained for the Bayer Pattern (qvalue) is in the hex form which needs to be decoded for setting the value of the variable pattern. The case statements indicate the various hex values relating to the Bayer Pattern that can be returned by the various cameras. The intimidating values are actually quite easy to decode. Here's the trick: The hex code for various colors is as follows:
Now if the qvalue contains 0x42474752, it means: B (42h) G (47h) G (47h) R (52h) or BGGR. We can therefore decode all the case statements similarly. Finally, we need to declare another image buffer that will contain the RGB image. Remember that the size of the RGB is 3 times the size of the Bayer Pattern image. rgbbuffer is therefore assigned 3 times the buffer size (camera.capture_buffer). This buffer (rgbbuffer) will be passed as the destination buffer (the second parameter in BayerNearestNeighbor). After the buffer has been filled with the RGB values we write it in the file image.rgb. In order to view this image using Gimp, we need to append a bitmap header. The method we employed was as follows:
In order to run the program, use the following steps:
The Coriander application is useful in finding out how the RGB image will look after undergoing different conversion algorithms. For example, it provides the choice between Nearest Neighbor, Edge Sense and Down Sample conversion algorithms. The difference can be observed on a mouse click. 4.6. Common Problems Faced While Working With IEEE1394 CamerasWe now look at some of the common problems faced while working with the camera, however we have only listed those problems which we faced. These problems are likely to be faced by anyone who uses the library and the camera. Some of the problems were solved with a proper reasoning but some were just hit-and-miss attempts. The problems and their solutions are listed below.
|




















