SOL9 2.0 Class: OpenCVImageView

 SOL9 C++ Class Library  SOL9 Samples  SOL9 Tutorial  SOL9 FAQ  SOL9 ClassTree  SOL9 ClassList 

Source code

/******************************************************************************
 *
 * Copyright (c) 2017 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.
 *
 *
 *  OpenCVImageView.h
 *
 *****************************************************************************/

// 2017/04/10
// 2017/04/25 Update to support mouse callback and label.

// This is a simple elementary container window for OpenCVNamedWindow 
// which has a resizable normal window style.

#pragma once

#include <sol/Static.h>
#include <sol/ClientDC.h>
#include <sol/PaintDC.h>
#include <sol/StringT.h>
#include <sol/Stdio.h>
#include <sol/ApplicationView.h>

#include <sol/opencv/OpenCVNamedWindow.h>
#include <sol/opencv/OpenCVMouseCallback.h>

namespace SOL {
  
  
class OpenCVImageView :public Composite {
private:
  SmartPtr<Static>            label;  //2017/04/25
  SmartPtr<OpenCVNamedWindow> namedWindow;
  StringT<char>               imageFileName;
  int                         imageLoadingFlag;
  OpenCVMouseCallback         mouseCallback;
  
public:
  //WM_DROPFILES event handler.
 long dropFiles(Event& event)
  {
    HWND hwnd = getWindow();
    callCallback(XmNdropCallback, (Key)hwnd, NULL, event);
    event.handled();
    return 1;
  }
 
  long paint(Event& event)
  {
    PaintDC dc(this);
    {
      //Call a virtual display method.
      //nameWindow->show(image);
      display();
    }
    event.handled();
    return 1L;
  }
  
  void resizeNamedWindow(int w, int h)
  {
    namedWindow -> reshape(0, 0, w, h);
  }
  
  void moveNamedWindow(int x, int y)
  {
    int w, h;
    namedWindow->getWindowSize(w, h);
    
    namedWindow -> move(x, y, w, h);
  }
  
  void resizeNamedWindow(int x, int y, double winw, double winh, double imw, double imh)
  {
    //Adjust the size of nameWindw to the size of cv::Mat.
    
    //Image size;
    double rw  = winw / imw;
    double rh  = winh / imh;
    //We change the size of namedWindow to fit imageSize keeping the aspecto ratio of mat image size.
    if (imw <= winw && imh <= winh) {
      if (rw >= rh) {
        namedWindow -> reshape(x, y, int(imw * rh), int(imh * rh));
      } else {
        namedWindow -> reshape(x, y, int(imw * rw), int(imh * rw));
      }
    } else if (imw > winw && imh <= winh) {
      if ( rw >= rh) {
        namedWindow->reshape(x, y, int(imw * rh), int(imh* rh) );
      } else  {
        namedWindow->reshape(x, y, int(imw * rw), int(imh* rw) );
      } 
    } else if (imw <= winw && imh > winh) {
      if ( rw <= rh) {
        namedWindow->reshape(x, y, int(imw * rw), int(imh* rw) );
      } else  {
        namedWindow->reshape(x, y, int(imw * rw), int(imh* rw) );
      } 
    } else if (imw >= winw && imh >= winh) {
      if ( rw >= rh) {
        namedWindow->reshape(x, y, int(imw * rh), int(imh* rh) );
      } else  {
        namedWindow->reshape(x, y, int(imw * rw), int(imh* rw) );
      } 
    }
  }

  void show(cv::Mat& mat)
  {
    if (namedWindow) {
     namedWindow -> show(mat); 
    }
  }
  
  //Pure virtual 
  virtual cv::Mat& getMat() = 0;

  //2017/07/25 Define your own setImage method in a subclass derived from this class. 
  virtual void setImage(cv::Mat& mat)
  {
  }
  
  virtual long size(Event& event)
  {
    int w, h;
    event.getSize(w, h);
    ClientDC cdc(this);
    SIZE size;
    cdc.getTextExtent(_T("A"), 1, &size);
    int h1 = size.cy;
    int x = 0;
    int y = 0; 

    if (label) {
      label-> reshape(0, 2, w, h1);
      //view    -> reshape(0, 3+h1, w, h-3-h1);
      y = h1 + 3;
      h = h - h1 -3;
    }
    if (namedWindow) {
      cv::Mat& mat = getMat();
      
      if (!mat.empty()) {
        double imw = (double)mat.cols; 
        double imh = (double)mat.rows;
        if (imw > 0.0 && imh > 0.0) {
          resizeNamedWindow(x, y, (double)w, (double)h, imw, imh);
        }
      }
    }
    event.handled();
    return 1;
  }
  
  void reshape(int x, int y, int w, int h)
  {
//    postResizeRequest(w, h);

    View::reshape(x, y, w, h);
    postResizeRequest(w, h);
  }
  
  cv::Mat readImage(const char* filename, int flag=CV_LOAD_IMAGE_COLOR)
  {
    imageFileName    = filename;
    imageLoadingFlag = flag;
    
    cv::Mat mat = cv::imread(filename, flag);
    if (mat.empty()) {
      throw IException("Failed to imread: %s  %d", filename, flag);
    }
    
    View::activate();
    setFocus();
    
    return mat;
  }

  cv::Mat reload()
  {
    return readImage((const char*)imageFileName, imageLoadingFlag);
  }
  

  void writeImage(const char* filename)
  {
    cv::Mat& mat = getMat();
    if (! cv::imwrite(filename, mat)) {
      throw IException("Failed to imwrite: %s", filename);
    }
  }
  
public:
  //Constructor
  OpenCVImageView(View* parent, const char* name, Args& args)
  :Composite(parent, name, 
            args.set(XmNclassName, "_OpenCVImageView_")
                .set(XmNbackground, (LONG_PTR)(COLOR_BTNFACE+1))
                .set(XmNexStyle,    (LONG_PTR)WS_EX_CONTROLPARENT)
                .set(XmNclassStyle, (LONG_PTR)CS_VREDRAW|CS_HREDRAW) //|CS_DBLCLICK)
                .set(XmNstyle,      (LONG_PTR)WS_CHILD|WS_VISIBLE|WS_CLIPCHILDREN|WS_CLIPSIBLINGS)
                                    )
  { 
    char winname[128];
    ULONG id = HandleToUlong(getWindow());
    sprintf_s(winname, CountOf(winname), "cvname_%ul", id);
    
    if (args.has(XmNlabelString)) {
      const char* string = (const char*)args.get(XmNlabelString);
      Args ar;
      label = new Static(this, string, ar);
    }
    
    Args ar;
    namedWindow = new OpenCVNamedWindow(this, winname, ar);
    
    addEventHandler(WM_PAINT, this,
          (Handler)&OpenCVImageView::paint, NULL);
    addEventHandler(WM_SIZE, this,
          (Handler)&OpenCVImageView::size, NULL);
    addEventHandler(WM_DROPFILES, this, 
        (Handler)&OpenCVImageView::dropFiles, this);
  }

  ~OpenCVImageView()
  {
  }
  
  void refresh()
  {
    postResizeRequest();
    View::refresh();
  }
  
  OpenCVNamedWindow* getNamedWindow()
  {
    return namedWindow;
  }
  
  void addCallback(const char* name, Object* object, Callback callback, void* data)
  {
    if (name == XmNdropCallback) {
      //1 Let this view accept WM_DROPFILES message.
      dragAcceptFiles(TRUE);
      View::addCallback(name, (const Key)getWindow(), object, callback, data);
    } else {
      View::addCallback(name, object, callback, data);      
    }
  }  
  
  //This will simply overwrite an existing mouseCallback entry if already registered, 
  //instead of adding a new entry.
  void addCallback(const char* name, Object* object, MouseCallback callback, void* data)
  {
    if (name == XmNmouseCallback) {
      const char* winname = (const char*)namedWindow->getWinName();
      mouseCallback.object   = object;
      mouseCallback.callback = callback;
      mouseCallback.data     = data;
    
      cvSetMouseCallback(winname, commonMouseCallback, this); 
    }
  }
 
private:
  // void (*CvMouseCallback )(int event, int x, int y, int flags, void* data);
  static void commonMouseCallback(int event, int x, int y, int flags, void* param)
  {
    OpenCVImageView* view = (OpenCVImageView*)param;
    if (view) {
      MouseCallback callback   = view->mouseCallback.callback;
      Object*         object   = view->mouseCallback.object;
      void*           data     = view->mouseCallback.data;
      //Call instant method callback of callee object.
      (object->*callback)(event, x, y, flags, data);
      
    }
  }
  
};

}



Last modified: 5 May 2019

Copyright (c) 2009-2019 Antillia.com ALL RIGHTS RESERVED.