Ask Your Question

Revision history [back]

Transform function in OpenCV on JNI error

I'm trying to implement the Xiao color transferring method on my Android application using openCV and JNI. I am using code from https://github.com/ZZPot/Multi-color-transfer and https://github.com/ZZPot/Xiao-transfer. I am running into this error when I get to my transform(img_4, result, mega) function:

OpenCV(3.4.1) Error: Assertion failed (scn == m.cols || scn + 1 == m.cols) in void cv::transform(cv::InputArray, cv::OutputArray, cv::InputArray), file /build/master_pack-android/opencv/modules/core/src/matmul.cpp, line 2088

I also had issues with this line:

Rect roi(0, 0, 3, 3);
U.copyTo(R(roi));

but when I changed it to:

Rect roi(0, 0, 4, 4);
U.copyTo(R(roi));

It stopped one of the errors. I'm not sure if this messed with the rest of the code at all.

#include <jni.h>
#include <string>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <vector>
#include <math.h>
using namespace std;
using namespace cv;
Mat makeCTXiao(Mat target, Mat source, Mat result);
void GetTRS(Mat input, Mat& T, Mat& R, Mat& S);
void GetSRT(Mat input, Mat& T, Mat& R, Mat& S);
Mat AddChannel(Mat mat);
Mat RemoveChannel(Mat mat);


extern "C"
JNIEXPORT void JNICALL
Java_com_mobileapps_bao_stylit_EditingModule_test(JNIEnv* env, jobject instance, jlong target,jlong source, jlong result) {

    cv::Mat* inMatTarget = (cv::Mat*)target;
    cv::Mat* inMatSource = (cv::Mat*)source;
    cv::Mat* outMat = (cv::Mat*)result;
    *outMat = makeCTXiao(*inMatTarget, *inMatSource, *outMat);

}

Mat makeCTXiao(Mat target, Mat source, Mat res)
{
    Mat imgs = source;
    Mat imgt = target;
    imgs.convertTo(imgs, CV_64FC3, 1 / 255.0);
    imgt.convertTo(imgt, CV_64FC3, 1 / 255.0);
    Mat src_T, src_R, src_S;
    Mat tar_T, tar_R, tar_S;
    GetTRS(imgs, src_T, src_R, src_S);
    GetSRT(imgt, tar_T, tar_R, tar_S);
    Mat mega = src_T * src_R * src_S * tar_S * tar_R * tar_T;

    Mat img_4 = AddChannel(imgt);
    Mat result;
    //transpose(mega, mega);
    transform(img_4, result, mega);
    //std::cout << result.at<Vec4d>(0, 0) << std::endl; // for original method it has enormous values for CV_64F. If should be from 0 to 1.0
    result = RemoveChannel(result);
    result.convertTo(result, CV_8UC3, 255);
    return result;
}
void GetTRS(Mat input, Mat& T, Mat& R, Mat& S)
{
    Mat cov, means;
    calcCovarMatrix(input.reshape(1, input.cols * input.rows), cov, means, CV_COVAR_NORMAL | CV_COVAR_ROWS, CV_64F);
    Mat U, A, VT;
    SVD::compute(cov, A, U, VT);
    T = Mat::eye(4, 4, CV_64FC1);
    R = Mat::eye(4, 4, CV_64FC1);
    S = Mat::eye(4, 4, CV_64FC1);

    Rect roi(0, 0, 4, 4);
    U.copyTo(R(roi));

    T.at<double>(0, 3) = means.at<double>(0, 0);
    T.at<double>(1, 3) = means.at<double>(0, 1);
    T.at<double>(2, 3) = means.at<double>(0, 2);

    // in original paper there is no sqrt()
    S.at<double>(0, 0) = sqrt(A.at<double>(0, 0));
    S.at<double>(1, 1) = sqrt(A.at<double>(1, 0));
    S.at<double>(2, 2) = sqrt(A.at<double>(2, 0));
}
void GetSRT(Mat input, Mat& T, Mat& R, Mat& S)
{
    Mat cov, means;
    calcCovarMatrix(input.reshape(1, input.cols * input.rows), cov, means, CV_COVAR_NORMAL | CV_COVAR_ROWS, CV_64F);
    Mat U, A, VT;
    SVD::compute(cov, A, U, VT);
    T = Mat::eye(4, 4, CV_64FC1);
    R = Mat::eye(4, 4, CV_64FC1);
    S = Mat::eye(4, 4, CV_64FC1);

    Rect roi(0, 0, 4, 4);
    invert(U, R(roi));

    T.at<double>(0, 3) = -means.at<double>(0, 0);
    T.at<double>(1, 3) = -means.at<double>(0, 1);
    T.at<double>(2, 3) = -means.at<double>(0, 2);

    S.at<double>(0, 0) = 1/sqrt(A.at<double>(0, 0));
    S.at<double>(1, 1) = 1/sqrt(A.at<double>(1, 0));
    S.at<double>(2, 2) = 1/sqrt(A.at<double>(2, 0));
}
Mat AddChannel(Mat mat)
{
    /*Mat img = Mat::ones(mat.size(), CV_64FC4);
    int from_to[] = {0,0, 1,1, 2,2};
    mixChannels(mat, img, from_to, 3);*/
    Mat img = Mat::ones(mat.size(), CV_64FC1);
    std::vector<Mat> channels;
    split(mat, channels);
    channels.push_back(img);
    merge(channels, img);
    return img;
}
Mat RemoveChannel(Mat mat)
{
    std::vector<Mat> channels;
    split(mat, channels);
    channels.resize(3);
    Mat img;
    merge(channels, img);
    return img;