Fourrier-Mellin with PostGIS- Part IV

Récupération par OpenCV du pointeur des données d’une bande

Dans cette nouvelle partie, nous allons faire d’une pierre deux coups: Nous allons wrapper dans du “extern “C” " l’algorithme de Reddy et Chatterji, implémenté par Thoduka. Quelques modifications devront être apportées à cette dernière.Son principe est simple: elle récupère deux images et essaie d’aligner l’une sur l’autre. L’idée centrale est que Postgres nous donnera accès aux bandes via un pointeur, aussi nous utiliserons OpenCV et plus exactement le constructeur Mat avec un tel pointeur.

La fonction ST_register

Cette fonction prendra, entre autres, deux pointeurs en argument: celui de la bande à aligner pband et celui de la bande de référence To_pband. La taille allouée est déterminée par les dimensions de l’image et l’espace occupé par un pixel. Pour ne pas alourdir nos codes, nous travaillerons avec des images mono-bande et des pixels d’un octet. Voici le code (“Wrapper_reg.cpp”):

#include "../include/imreg_fmt/image_registration.h"
#include "Wrapper_reg.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

extern "C" {
  
	uchar* 
	ST_register(int height,int width,char type, void* pband,void* To_pband,int rowbytes){
    
    /* Only the constructors change compared to Thoduka's main program*/
	
    cv::Mat im0= cv::Mat(height,width,type,pband, rowbytes);
    cv::Mat im1= cv::Mat(height,width,type,To_pband, rowbytes);
	
    /*DEBUG*/
    cv::imshow("im0", im0);
    cv::imshow("im1", im1);
    cv::waitKey(0);
    /*DEBUG*/
	
    ImageRegistration image_registration(im0);
    std::cout << "Registered OK ";
    // x, y, rotation, scale
    std::vector<double> transform_params(4, 0.0);
	
	/* registered_image is the transformed image */
	
    cv::Mat registered_image;
    image_registration.registerImage(
		im1, registered_image, transform_params, true
	);


    std::cout << "x: " << transform_params[0] << ", y: "
              << transform_params[1] << ", rotation: " << transform_params[2]
              << ", scale: " << transform_params[3] << std::endl;
    
    /* We return the uchar* to the registered image in order to allow Postgres 
	to store it later */
	
    return registered_image.data;
	}
};

Le header (“Wrapper_reg.hpp”) ne comporte rien de particulier, nous passons cette étape.

Pour tester ce Wrapper (et le débuguer) nous pouvons écrire un petit programme qui lit deux images en noir et blanc (et de même dimensions) et consomme notre wrapper en lui fournissant les pointeurs vers les données (“main_wrapper.cpp”):

#include "../include/imreg_fmt/image_registration.h"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include "Wrapper_reg.hpp"

int  main(int argc, char **argv)
{
    cv::Mat im0, im1;
    uchar* data_reg;
    int height,width,rowbytes;
    void* pband;
    void* To_pband;
    
    std::string image_path = cv::samples::findFile("sample1.png");
    im0 = cv::imread(image_path, cv::IMREAD_GRAYSCALE);
    image_path = cv::samples::findFile("sample3.png");
    im1 = cv::imread(image_path, cv::IMREAD_GRAYSCALE);
    height=im0.rows;
    width=im0.cols;
    rowbytes= width * 1;
    pband=(void *)im0.data;
    To_pband=(void*)im1.data;
    data_reg=ST_register(height,width,/*cv::CV_8UC1*/0,pband,To_pband,rowbytes);
    if (data_reg){
      printf("Success");
    }
    return 0;
}

Notons qu’OpenCV fournit un pointeur vers les bandes comme un uchar* mais que le constructeur attend un void*, d’où les cast effectués ( pband=(void *)im0.data;).

La compilation ne devrait pas trop poser de problèmes, bien qu’il faille insérer

#define OPENCV_DISABLE_EIGEN_TENSOR_SUPPORT 

au début du fichier image_registration.cpp sans quoi le header, inexistant, vers les fonctions gérant les tenseurs est requis!

g++ -Wall -c image_registration.cpp `pkg-config opencv4 --cflags --libs` 
-o image_registration.o
g++ -Wall -c image_dft.cpp `pkg-config opencv4 --cflags --libs` 
-o image_dft.o
g++ -Wall -c image_transforms.cpp `pkg-config opencv4 --cflags --libs` 
-o image_transforms.o
g++ -c -Wall Wrapper_reg.cpp `pkg-config opencv4 --cflags --libs` 
-o Wrapper_reg.o
g++ -Wall -c main_wrapper.cpp `pkg-config opencv4 --cflags --libs` 
-o main_wrapper.o
g++ image_dft.o image_registration.o image_transforms.o main_wrapper.o 
Wrapper_reg.o `pkg-config opencv4 --cflags --libs` -lfftw3 -o main_wrapper

Il suffit donc de linker contre “pkg-config opencv4 --cflags --libs” et “fftw3”

Nous pouvons donc constater que notre Wrapper d’openCV fonctionne bien. Nous allons donc pouvoir l’utiliser depuis Postgres. Notons qu’ayant utilisé des fonctions du coeur de l’extension raster, c’est en réalité touteb l’extension que nous devons compiler et il s’avère en fait plus simple de compiler PostGIS en y ayant intégré notre travail. Ceci fera l’objet de notre dernier article concernant cette introduction.