Skip to content

File Image.cpp

File List > AIAC > Image.cpp

Go to the documentation of this file

// #####################################################################
// >>>>>>>>>>>>>>>>>>>>> BEGINNING OF LEGAL NOTICE >>>>>>>>>>>>>>>>>>>>>
//######################################################################
//
// This source file, along with its associated content, was authored by
// Andrea Settimi, Hong-Bin Yang, Naravich Chutisilp, and numerous other
// contributors. The code was originally developed at the Laboratory for
// Timber Construction (IBOIS, director: Prof. Yves Weinand) at the School of 
// Architecture, Civil and Environmental Engineering (ENAC) at the Swiss
// Federal Institute of Technology in Lausanne (EPFL) for the Doctoral
// Research "Augmented Carpentry" (PhD researcher: Andrea Settimi,
// co-director: Dr. Julien Gamerro, director: Prof. Yves Weinand).
//
// Although the entire repository is distributed under the GPL license,
// these particular source files may also be used under the terms of the
// MIT license. By accessing or using this file, you agree to the following:
//
// 1. You may reproduce, modify, and distribute this file in accordance
//    with the terms of the MIT license.
// 2. You must retain this legal notice in all copies or substantial
//    portions of this file.
// 3. This file is provided "AS IS," without any express or implied
//    warranties, including but not limited to the implied warranties of
//    merchantability and fitness for a particular purpose.
//
// If you cannot or will not comply with the above conditions, you are
// not permitted to use this file. By proceeding, you acknowledge and
// accept all terms and conditions herein.
//
//######################################################################
// <<<<<<<<<<<<<<<<<<<<<<< END OF LEGAL NOTICE <<<<<<<<<<<<<<<<<<<<<<<<
// #####################################################################
//
#include "aiacpch.h"

#include "AIAC/Image.h"

#include "stb/stb_image.h"
#include "stb/stb_image_write.h"

namespace AIAC
{
    Image::Image() {}
    Image::Image(cv::Mat cvImg) { UpdateData(cvImg); }
    Image::Image(AIAC::Image &img) { UpdateData(img.m_CvMat); }
    Image::Image(const char *path, int cvImReadFlag) {
        cv::Mat cvImg = cv::imread(path, cvImReadFlag);
        UpdateData(cvImg);
    }

    Image::~Image() { DeleteGlTexture(); }

    void Image::UpdateData(cv::Mat cvImg)
    {
        cvImg.copyTo(m_CvMat);
        cvImg.copyTo(m_PureCvMat);

        switch (cvImg.channels())
        {
        case 1:
            m_Format = ImageFormat::GRAYSCALE; break;
        case 3:
            cv::cvtColor(m_CvMat, m_CvMat, cv::COLOR_BGR2RGB);
            m_Format = ImageFormat::RGB; break;
        case 4:
            cv::cvtColor(m_CvMat, m_CvMat, cv::COLOR_BGRA2RGBA);
            m_Format = ImageFormat::RGBA; break;
        default:
            m_Format = ImageFormat::None; break;
        }

        m_DataUpdatedAfterGenImTexture = true;
        m_DataUpdatedAfterGenGlTexture = true;

        DeleteGlTexture();
    }


    GLuint Image::GetGlTextureObj()
    {
        if(!HasGlTextureObj() || m_DataUpdatedAfterGenGlTexture){
            UpdateGlTextureObj();
        }
        return m_GlTextureObj;
    }

    ImTexture Image::GetImTexture(ImVec2 size){
        if(!HasImTexture() || m_DataUpdatedAfterGenImTexture){
            UpdateGlTextureObj();
            UpdateImTexture();
        }
        if(size.x != 0 && size.y != 0)
            SetImTextureSize(size);

        return m_ImTexture;
    }

    void Image::UpdateGlTextureObj(){
        if(m_CvMat.empty()) { AIAC_ERROR("Image's cv::Mat is empty!"); return ; }

        GLint glInternalFormat;
        switch(m_Format){
        case ImageFormat::GRAYSCALE:
            glInternalFormat = GL_LUMINANCE; break;
        case ImageFormat::RGB:
            glInternalFormat = GL_RGB; break;
        case ImageFormat::RGBA:
            glInternalFormat = GL_RGBA; break;
        default:
            glInternalFormat = GL_RGB; break;
        }
        CvtCvMat2GlTextureObj(m_CvMat, m_GlTextureObj, glInternalFormat);
        m_DataUpdatedAfterGenGlTexture = false;
    }

    void Image::UpdateImTexture(){
        if(m_CvMat.empty()) { AIAC_ERROR("Image's cv::Mat is empty!"); return ; }
        UpdateGlTextureObj();
        CvtGlTextureObj2ImTexture(m_GlTextureObj, m_ImTexture);
        m_DataUpdatedAfterGenImTexture = false;
    }

    // >>Operator for cv video reading API
    void operator>>(cv::VideoCapture cap, AIAC::Image &img)
    {
        cv::Mat cvImg;
        cap >> cvImg;
        img.UpdateData(cvImg);
    }

    // Utilities functions
    void CvtGlTextureObj2ImTexture(GLuint glTextureObj, ImTexture& imTexture, ImVec2 size)
    {
        imTexture.ID = (void*)(intptr_t)glTextureObj;
        imTexture.Size = size;
    }

    void CvtCvMat2GlTextureObj(cv::Mat& cvMat, GLuint& glTextureObj, GLint glInternalFormat)
    {
        if(cvMat.empty()) { AIAC_ERROR("cvMat empty"); return; }
        else
        {
            if(glTextureObj != 0) { glDeleteTextures(1, &glTextureObj); }
            cv::Mat flippedCvMat;
            cv::flip(cvMat, flippedCvMat, 0);  // OpenGL flip images by default?
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
            glGenTextures(1, &glTextureObj);
            glBindTexture(GL_TEXTURE_2D, glTextureObj);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

            glTexImage2D(GL_TEXTURE_2D,
                         0,
                         glInternalFormat,
                         flippedCvMat.cols,
                         flippedCvMat.rows,
                         0,
                         glInternalFormat,
                         GL_UNSIGNED_BYTE,
                         flippedCvMat.ptr());
        }
    }

    void CvtCvMat2ImTexture(cv::Mat& cvMat, ImTexture& imTexture, GLuint &glTextureObj, GLint glInternalFormat)
    {
        CvtCvMat2GlTextureObj(cvMat, glTextureObj, glInternalFormat);
        CvtGlTextureObj2ImTexture(glTextureObj, imTexture);
    }
}