OZ++ Class: OpenCVImageView
/******************************************************************************
 *
 * 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
 *
 *****************************************************************************/

#pragma once

#include <oz++/Exception.h>
#include <oz++/motif/Pixelmap.h>
#include <oz++/motif/Canvas.h>
#include <oz++/opencv/OpenCVImageConverter.h>

namespace OZ {

class OpenCVImageView: public Canvas {

private:
  Pixmap  pixmap;
  cv::Mat rgbImage;

public:
  //Please redefine a virtual display method in your own class 
  //derived from this OpenView class.
  virtual void display()
  {
     printf("OpenImageView::display\n");
  }

  virtual void scaleImage(cv::Mat& originalImage, cv::Mat& scaledImage, 
   int scalingRatio)
  {
    try {
      if (scalingRatio < 1) {
       scalingRatio = 10;
      }
      float ratio = (float)scalingRatio/100.0f;

      cv::resize(originalImage, scaledImage, cv::Size(), 
        ratio, ratio);
      //2017/05/18
      invalidate();
      refresh();
      //  
     } catch (cv::Exception& ex) {
         ;
     }
  }

  void resizeToImageSize(cv::Mat& image)
  {
    if (!image.empty()) {
      Dimension w = image.cols;
      Dimension h = image.rows;
      resize(w, h);
    }
  }

  cv::Mat readImage(const char* filename, int loadingFlag)
  {
     cv::Mat image = imread(filename, loadingFlag);
     if (image.empty()) {
       throw IException("Failed to imread: %s", filename);
     }
     return image;
  }

  void invalidate()
  {
    pixmap = None;
    rgbImage.release();
  }

  void show(cv::Mat& mat)
  {
    if (!mat.empty()) {
      if (pixmap == None) {
        dprintf("show d =%d c=%d\n", mat.depth(), mat.channels());

        if ( mat.channels() == 1) {
          // if mat is grayscale, we convert  to rgbImage
          dprintf("Convert grayscale image to rgb image\n");
          rgbImage.release();
          cvtColor(mat, rgbImage, CV_GRAY2RGB);
          pixmap = OpenCVImageConverter::convertToPixmap(this, rgbImage);

        } else if ( mat.channels() ==3) { 
          // mat is rgbImage  
          pixmap = OpenCVImageConverter::convertToPixmap(this, mat);
        } else {
          throw IException("Unsupported cv::Mat image");
        }
      }
      
      if (pixmap != None) {
        DC dc(this);
        Display* display = dc.getDisplay();
        Drawable src  = pixmap;
        Drawable dst  = dc.getDrawable();
        GC       gc   = dc.getGC();
        dc.copyArea(src, 0, 0, width(), height(), 0, 0);

        //flush(); //XFlush
      }
    }
  }

  virtual void expose(Action& action)
  {
    //Call a virtual display method to display OpenGL figures.
    display();
    //flush(); //XFlush
  }

  void reshape(int x, int y, int w, int h)
  {
    View::resize(x, y, w, h, 0);
  }

public:
  OpenCVImageView(View* parent, const char* name, Args& args)
  :Canvas(parent, name,  args.set(XmNtraversalOn,False))
  ,pixmap(None)
  {
  }

  ~OpenCVImageView()
  {
    rgbImage.release();
  }
    
  virtual void save(const char* filename, const cv::Mat& image)
  {
    if (!image.empty()) {
      if (!imwrite(filename, image)) {
        throw IException("Failed to write image file: %s", filename);
      }
    }
  }

  void rescale(cv::Mat& image, cv::Mat& scaledImage, int scalingRatio)
  {
    if (scalingRatio < 1) {
      scalingRatio = 10;
    }
    float ratio = (float)scalingRatio/100.0f;

    cv::resize(image, scaledImage, cv::Size(),
                ratio, ratio);
  }

  void refresh()
  {
    sendExposeEvent();
  }
};

}