OZ++ Sample: ObjectDetector |
/******************************************************************************
*
* Copyright (c) 2019 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* ObjectDetector.cpp
*
*****************************************************************************/
//2017/5/20 Modified to use OpenCVScrolledImage instead of OpenCVImageView
// to reduce excessive screen flickering on a window resizing.
//2019/01/03
#include <opencv2/stitching.hpp>
#include <oz++/motif/Label.h>
#include <oz++/motif/TextField.h>
#include <oz++/motif/PushButton.h>
#include <oz++/motif/RowColumn.h>
#include <oz++/motif/FileDropdownComboBox.h>
#include <oz++/motif/FileOpenDialog.h>
#include <oz++/motif/FolderOpenDialog.h>
#include <oz++/opencv/OpenCVMainView.h>
#include <oz++/opencv/OpenCVImageView.h>
#include <oz++/opencv/OpenCVScrolledImageView.h>
#include <oz++/opencv/OpenCVScaleComboBox.h>
#include <opencv2/objdetect/objdetect.hpp>
namespace OZ {
class MainView : public OpenCVMainView {
private:
//////////////////////////////////////////////
//Inner class starts.
class SimpleView :public OpenCVScrolledImageView {
private:
cv::Mat originalImage;
cv::Mat scaledImage;
void display()
{
show(scaledImage);
}
public:
SimpleView(View* parent, const char* name, Args& args)
:OpenCVScrolledImageView(parent, name, args)
{
const char* filename = "";
int loadingFlag = 1;
int scalingRatio = 100;
if (args.has(XmNimageFileName)) {
filename = (const char*)args.get(XmNimageFileName);
}
if (args.has(XmNimageLoadingFlag)) {
loadingFlag = (int)args.get(XmNimageLoadingFlag);
}
if (args.has(XmNimageScalingRatio)) {
scalingRatio = (int)args.get(XmNimageScalingRatio);
}
loadImage(filename, loadingFlag, scalingRatio);
}
void loadImage(const char* filename, int loadingFlag, int scalingRatio)
{
originalImage = readImage(filename, loadingFlag);
scaleImage(originalImage, scaledImage, scalingRatio);
}
void rescale(int scalingRatio)
{
scaledImage.release();
scaleImage(originalImage, scaledImage, scalingRatio);
}
void clear(int scalingRatio)
{
rescale(scalingRatio);
}
void detect(const char* path, int scalingRatio)
{
try {
CascadeClassifier classifier;
classifier.load(path);
cv::vector<Rect> faces;
classifier.detectMultiScale(originalImage, faces, 1.1, 3, 0, cv::Size(20,20));
if (faces.size() == 0) {
// MessageBox(NULL, "Not detected by detectMultiScale.",
// "DetectOperation", MB_OK|MB_ICONINFORMATION);
}
for (int i = 0; i < faces.size(); i++){
rectangle(originalImage, Point(faces[i].x, faces[i].y),
Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height),
Scalar(0, 200, 0), 3, CV_AA);
}
scaleImage(originalImage, scaledImage, scalingRatio);
} catch (Exception& ex) {
caught(ex);
}
}
};
//Inner class ends.
//////////////////////////////////////////////
//SmartPtr<BulletinBoard> bboard;
SmartPtr<TextField> filePath;
SmartPtr<Label> classifierLabel;
SmartPtr<FileDropdownComboBox> classifierComboBox;
SmartPtr<PushButton> folderButton;
StringT<char> classifierFolder;
SmartPtr<SimpleView> view;
SmartPtr<RowColumn> controlPane;
SmartPtr<OpenCVScaleComboBox> scaleComboBox;
SmartPtr<PushButton> reloadButton;
SmartPtr<PushButton> detectButton;
SmartPtr<FileOpenDialog> fileDialog;
SmartPtr<FolderOpenDialog> folderDialog;
StringT<char> imageFileName;
int imageLoadingFlag;
int imageScalingRatio;
void fileOpen(Action& action)
{
fileDialog->popup();
}
void updateLabel(const char* filename)
{
CompoundString cs(filename);
filePath->set(XmNlabelString, cs);
filePath->setString(filename);//, cs);
}
void scaleChanged(Action& action)
{
int val = scaleComboBox->getScale();
if (val > 0 && imageScalingRatio != val) {
imageScalingRatio = val;
view -> rescale(imageScalingRatio);
}
}
void showFolderBrowser(Action& action)
{
folderDialog->popup();
}
void ok(Action& action)
{
try {
const char* filename = fileDialog->getFileName();
imageFileName = filename;
printf("filename: %s\n", filename);
fileDialog->popdown();
view->invalidate();
view->loadImage(filename,
imageLoadingFlag, imageScalingRatio);
updateLabel(filename);
resize(width(), height());
//flush();
} catch (OZ::Exception& ex) {
caught(ex);
}
}
void selectFolder(Action& action)
{
classifierFolder = folderDialog->getFolderName();
printf("selectFolder %s\n", (const char*)classifierFolder);
folderDialog->popdown();
classifierComboBox->listupFiles((const char*)classifierFolder, "*.xml");
}
void reload(Action& action)
{
view -> loadImage(imageFileName,
imageLoadingFlag,
imageScalingRatio);
}
void detect(Action& action)
{
XmString xms;
classifierComboBox->get(XmNselectedItem, (XtArgVal)&xms);
CompoundString cs(xms);
char* item = NULL;
cs.get(&item);
if (item != NULL) {
char classifierxml[PATH_MAX];
sprintf(classifierxml, "%s/%s", (const char*)classifierFolder,
item);
printf("detect xml=%s\n", classifierxml);
view -> detect(classifierxml, imageScalingRatio);
}
XtFree(item);
}
void resize(Dimension w, Dimension h)
{
int CP_WIDTH = 160;
int ww = w-CP_WIDTH;
static int LH = 0;
if (LH == 0) {
LH = filePath->height();
}
static int CH = 0;
if (CH == 0) {
CH = classifierComboBox->height();
}
static const int CL_WIDTH = 100;
static const int FB_WIDTH = 60;
if (filePath && classifierComboBox && view && controlPane ) {
BulletinBoard* bboard = getBulletinBoard();
//bboard->unmap();
//bboard->unmanage();
int lh = LH;
int ch = CH;
int m = 2;
filePath -> reshape(m, m, w, lh+m);
classifierLabel -> reshape(m, lh+2*m, CL_WIDTH, CH);
classifierComboBox -> reshape(2*m+CL_WIDTH, lh+2*m, w-CL_WIDTH-FB_WIDTH-4*m, CH);
folderButton -> reshape(w - FB_WIDTH, lh+2*m+m, FB_WIDTH-m, LH);
view -> reshape(m, lh+2*m + ch+2*m, ww-2*m,
h - lh - ch -4*m-ch);
Window cw = controlPane->getWindow();
controlPane -> reshape(ww-1, lh+2*m + ch+2*m, CP_WIDTH+1,
h - lh - ch-4*m);
//controlPane -> unmap();
//controlPane -> map();
//bboard->manage();
//bboard->map();
}
}
public:
MainView(OpenCVApplication& applet, const char* name, Args& args)
:OpenCVMainView(applet, name, args)
{
BulletinBoard* bboard = getBulletinBoard();
try {
Args ar;
ar.reset();
imageFileName = "../images/WafukuMannequin.png";
imageLoadingFlag = CV_LOAD_IMAGE_COLOR;
imageScalingRatio = 100;
//1 Create a filePath to display a filename.
ar.set(XmNalignment, XmALIGNMENT_BEGINNING);
filePath = new TextField(bboard, "", ar);
filePath -> setEditable(FALSE);
updateLabel(imageFileName);
CompoundString classifiercs("Classifier");
ar.reset();
ar.set(XmNalignment, XmALIGNMENT_BEGINNING);
ar.set(XmNlabelString, classifiercs);
classifierLabel = new Label(bboard, "", ar);
CompoundString foldercs("...");
ar.reset();
ar.set(XmNlabelString, foldercs);
folderButton = new PushButton(bboard, "", ar);
folderButton -> addCallback(XmNactivateCallback, this,
(Callback)&MainView::showFolderBrowser, NULL);
ar.reset();
classifierComboBox = new FileDropdownComboBox(bboard, "", ar);
//2 Create a simpleview.
ar.reset();
ar.set(XmNimageFileName, imageFileName);
ar.set(XmNimageLoadingFlag, imageLoadingFlag);
ar.set(XmNimageScalingRatio, imageScalingRatio);
view = new SimpleView(bboard, "", ar);
//3 Create a controlPane.
ar.reset();
controlPane = new RowColumn(bboard, "", ar);
//4 Create a scaleComboBox.
const char* defaultScale = "100%";
ar.reset();
CompoundString scaler("Scale");
ar.set(XmNlabelString, scaler);
ar.set(XmNdefaultScale, defaultScale);
scaleComboBox = new OpenCVScaleComboBox(controlPane, "", ar);
scaleComboBox->addCallback(XmNselectionCallback, this,
(Callback)&MainView::scaleChanged, NULL);
CompoundString reloadcs("Reload");
ar.reset();
ar.set(XmNlabelString, reloadcs);
reloadButton = new PushButton(controlPane, "", ar);
reloadButton -> addCallback(XmNactivateCallback, this,
(Callback)&MainView::reload, NULL);
CompoundString detectcs("Detect");
ar.reset();
ar.set(XmNlabelString, detectcs);
detectButton = new PushButton(controlPane, "", ar);
detectButton -> addCallback(XmNactivateCallback, this,
(Callback)&MainView::detect, NULL);
const char* home = getenv("HOME");
//5 Create a fileOpendialog
ar.reset();
ar.set(XmNrootFolderName, home);
fileDialog = new FileOpenDialog(this, "FileOpenDialog", ar);
fileDialog -> getOkButton()
-> addCallback(XmNactivateCallback, this,
(Callback)&MainView::ok, NULL);
//5 Create a folderOpenDialog
ar.reset();
ar.set(XmNrootFolderName, home);
folderDialog = new FolderOpenDialog(this, "FolderOpenDialog", ar);
folderDialog -> getOkButton()
-> addCallback(XmNactivateCallback, this,
(Callback)&MainView::selectFolder, NULL);
} catch (OZ::Exception& ex) {
caught(ex);
}
}
~MainView()
{
}
};
}
//
int main(int argc, char** argv)
{
try {
const char* appclass = argv[0];
OpenCVApplication applet(appclass, argc, argv);
Args args;
args.set(XmNwidth, 800);
args.set(XmNheight, 460);
MainView view(applet, argv[0], args);
view.realize();
applet.run();
} catch (OZ::Exception& ex) {
caught(ex);
}
return 0;
}