C ++ development of face and gender recognition tutorial (9) -- Build an MFC framework to display images
In the previous blog, we have read the folder selected by the user and saved its path to the corresponding variable, in this blog, we will show you how to use the CvvImage class to display images in the picture control and automatically read other images in the folder.
1. Add the "Next" button
Because we need to read all the image files in the folder, instead of a specific file, it is necessary to add a button for control. The specific function is: each click this button, the program will automatically read the next image and display it on the interface. Since we have already introduced in detail how to add the Button control in MFC, we will not go into details here. Add a button named "Next" and change the ID to IDC_BUTTON_NextImage:
Ii. Write traversal Functions
As mentioned in the previous blog, after selecting a folder, the program saves the folder path in the m_Path variable. Next we will use this variable to further traverse the image files under its path. Here we write a function specifically to implement the "review an image" function, named GetNextBigImg. Therefore, you need to add this member function to the CGenderRecognitionMFCDlg class. In the class view, right-click the corresponding class and select "Add-> Add function" from the shortcut menu. Enter the function attributes:
The GetNextBigImg () function mainly undertakes the following tasks:
1. Start traversing
Call the GetNextBigImg () function at the end of the OnBnClickedButtonImagefile () function to enable the file reader after clicking the "image folder" button to read the folder information.
2. Read a file from the current directory
The readdir function is used to read files. Considering that you may select an empty folder, you must make a judgment on the read operation:
if (m_pDir && (m_pEnt = readdir(m_pDir)) != NULL) { }
The readdir () function can read the files in the current directory structure (m_pDir) in a non-repeating order, that is, each read is automatically moved to the next file to be read, similar to the pointer mechanism, the readdir () function is included in dirent. h. The header file has been added and included. In this case, the file name is saved in the m_pEnt variable:
3. Determine whether it is an image file
The strstr () function is used to determine whether the file name contains the corresponding extension string. The default image formats include jpg, bmp, and png:
If (m_pDir & (m_pEnt = readdir (m_pDir ))! = NULL) {/*********** determine whether the image file is **********/char * jpg = strstr (m_pEnt-> d_name, ". jpg "); char * bmp = strstr (m_pEnt-> d_name ,". bmp "); char * png = strstr (m_pEnt-> d_name ,". png ");}
For the call format "m_pEnt-> d_name", it is clearly defined in the dirent. h header file. If you have any questions, you can refer to the relevant files. Next, determine whether the file is an image file by determining whether the variables jpg, bmp, and png are null:
If (m_pDir & (m_pEnt = readdir (m_pDir ))! = NULL) {/*********** determine whether the image file is **********/char * jpg = strstr (m_pEnt-> d_name, ". jpg "); char * bmp = strstr (m_pEnt-> d_name ,". bmp "); char * png = strstr (m_pEnt-> d_name ,". png "); if (jpg = NULL & bmp = NULL & png = NULL) // if the file is not an image file {GetNextBigImg ();} else {/*********** show this image **********/}}
Note that a recursive method is used to round-robin non-image files. That is, when the current file is determined to be a non-image file (jpg, bmp, and png are empty ), call itself to GetNextBigImg (), which means to execute the readdir () function again, so that the file pointer is moved back, and the final file traversal is implemented recursively. Correspondingly, if the current file is one of the three image files, draw the current image to the picture control, and then write the code to draw the image.
4. Draw an image to the picture control
Now it's CvvImage's turn. Before that, we need to associate a rectangle variable of the CRect type with the picture control, which will be used to save the position of the picture control in the customer zone. First, add the member variable m_PicCtlRect to the CGenderRecognitionMFCDlg class:
Then, add an HDC (handle) variable m_pPicCtlHdc to save the control handle:
Then, write two lines of code in the initialization function OnInitDialog () in the dialog box of CGenderRecognitionMFCDlg to associate controls, handles, and locations:
/********* Initialize the picture control **********/m_pPicCtlHdc = GetDlgItem (IDC_PICTURE)-> GetDC () -> GetSafeHdc (); // return control handle GetDlgItem (IDC_PICTURE)-> GetClientRect (m_PicCtlRect); // associate control location
You can add the two statements to the end of OnInitDialog (). There are three problems to emphasize:
(1) Why does the handle and CRect variables need to be used? The reason is simple. CvvImage class requirements. Here we will introduce a tips for viewing function parameters, that is, entering a comma in the brackets of the function name, VS will automatically give the format of the function parameters:
It can be seen that the DrawToHDC function requires two parameters: one is of the HDC type and the other is of the RECT * type.
(2) How to quickly find the class member functions? The most direct method is to browse through the Class View by clicking the corresponding class:
Of course, you can also use the search bar above.
(3) OnInitDialog function. This function is executed when the program starts to construct the MFC framework. Therefore, initialization operations on the control should be performed in this function, not the constructor.
Now that the preparation is complete, you can add the formal display code for the GetNextBigImg () function:
/********** Display the image ***********/IplImage * imageSrc; CvvImage imageSrcCvvImg; char imageFullName [500]; // Save the full path sprintf_s of the image file (imageFullName, "% s", m_ImageDir, m_pEnt-> d_name); // spell out the full path imageSrc = cvLoadImage (imageFullName ); imageSrcCvvImg. copyOf (imageSrc); imageSrcCvvImg. drawToHDC (m_pPicCtlHdc, m_PicCtlRect); cvReleaseImage (& imageSrc );
In this case, run the program and click "image folder" to select a folder containing image files. The program displays images normally:
5. Add the "Next" Function
Next, we will specify its function for the "Next" button on the interface. Double-click the "Next" button to add the response function:
Since we have previously encapsulated image polling and display operations in the GetNextBigImg () function, Here we only need to call this function to implement the "Next" function:
Void CGenderRecognitionMFCDlg: OnBnClickedButtonNextimage () {GetNextBigImg (); // TODO: add control notification handler code here}
OK.
Iii. Summary
After this blog post, our MFC framework already has the basic image display function. In the next blog, we will add the facial detection function to it. Pay attention to several issues.
1. OpenCv2.x questions about image display
The CvvImage method used here is based entirely on OpenCv1.x and uses the IplImage variable to represent images.
2. Recursive Layers
Here, the GetNextBigImg () function has a recursive call process, and the recursive depth must be considered when recursion exists. Every time a non-image file is traversed, a layer is added to the recursive depth. If the recursive depth is exceeded, the program will crash, from this perspective, recursive methods are used to poll image files and non-image files, which poses a serious BUG. As long as there are enough non-image files in the folder, the program will inevitably crash due to infinite recursion. I believe everyone can find other safer ways to solve this problem.