Repository: opencv
Issue: ThinPlateSplineShapeTransformer::wrapImage transformed X and Y values are located in the oposite side
Labels: bug,affected: 3.4,category: shape

<!--
If you have a question rather than reporting a bug please go to http://answers.opencv.org where you get much faster responses.
If you need further assistance please read [How To Contribute](https://github.com/opencv/opencv/wiki/How_to_contribute).

This is a template helping you to create an issue which can be processed as quickly as possible. This is the bug reporting section for the OpenCV library.
-->
##### System information (version)

<!-- Example
- OpenCV => 3.1
- Operating System / Platform => Windows 64 Bit
- Compiler => Visual Studio 2013
-->
- OpenCV => 3.1
- Operating System / Platform => Windows 64 Bit
- Compiler => Visual Studio 2013
##### Detailed description

Hi,

I'm working with the ThinPlateSplineShapeTransformer. I tried the methods **estimateTransformation**, **applyTransformation** and **warpImage**. It seems there is a bug in the ThinPlateSplineShapeTransformer::warpImage implementation where transformed X values are located in the oposite side. The same behavior for the Y values. 
##### Steps to reproduce

First, I tried only the **estimateTransformation** and **applyTransformation** methods.

``` cpp
    auto tps = cv::createThinPlateSplineShapeTransformer();
    std::vector<cv::Point2f> sourcePoints, targetPoints;
    sourcePoints.push_back(cv::Point2f(0, 0));
    targetPoints.push_back(cv::Point2f(100, 0));
    sourcePoints.push_back(cv::Point2f(799, 0));
    targetPoints.push_back(cv::Point2f(799, 0));
    sourcePoints.push_back(cv::Point2f(0, 599));
    targetPoints.push_back(cv::Point2f(0, 599));
    sourcePoints.push_back(cv::Point2f(799, 599));
    targetPoints.push_back(cv::Point2f(799, 599));

    std::vector<cv::DMatch> matches;
        for (unsigned int i = 0; i < sourcePoints.size(); i++)
            matches.push_back(cv::DMatch(i, i, 0));

    tps->estimateTransformation(sourcePoints, targetPoints, matches);
    std::vector<cv::Point2f> transPoints;
    tps->applyTransformation(sourcePoints, transPoints);

    cout << "sourcePoints = " << endl << " " << sourcePoints << endl << endl;
    cout << "targetPoints = " << endl << " " << targetPoints << endl << endl;
    cout << "transPos = " << endl << " " << transPoints << endl << endl;
```

So, we want to transform 4 points (sourcePoints) into 4 targetPoints (targetPoints). In line 4 the source point (0,0) should be transformed to the target point (100, 0). In other words: The target point is 100 units moved to the right. We assume that we have a x axis which will be positive to the right. 
Then we match the 4 source to the target points with cv::DMatch. And then we call **estimateTransformation** to perform the thin plate spline implementation. And finally we prove the tranformation with the method **applyTransformation**. The transformed points "transPoints" should be equal to the targetPoints.
And thats true. The output is:

```
sourcePoints =
 [0, 0;
 799, 0;
 0, 599;
 799, 599]

targetPoints =
 [100, 0;
 799, 0;
 0, 599;
 799, 599]

transPos =
 [100.00003, 0;
 799, 0;
 4.196167e-005, 599;
 799, 599]
```

Hurrah. The **estimateTransformation** and **applyTransformation** methods work as expected.

But now we want to apply the transformation for a "real" image with **warpImage**. Be aware that the origin of an "image" is in the upper left corner. So the y axis goes from up to down and the x axis goes from left to right.

I added only these few lines of code to the above code

``` cpp
    cv::Mat img = cv::imread("C:/tests/ThinPlateSplineShapeTransformer/t.png");
    cv::imshow("input", img);
    cv::Mat res;
    tps->warpImage(img, res);
    cv::imshow("warp result", res);
```

Here is the input image:
![t](https://cloud.githubusercontent.com/assets/3143027/17549564/17c013b4-5ef1-11e6-8dda-94b57f6fa798.png)
But the wrapped image is not correct. It seems that the point (0,0) is transformed to (-100, 0) or somewhere else.
![wrapresult](https://cloud.githubusercontent.com/assets/3143027/17549689/ca3ededa-5ef1-11e6-9c15-785bae676081.png)

A work-around is to switch sourcePoints and targetPoints in **estimateTransformation**

``` cpp
// **** Switch source and target points so that wrapImage is working correctly. ****
tps->estimateTransformation(targetPoints, sourcePoints, matches); 
```

After the "switch" the wrap result is correct:
![wrapresult](https://cloud.githubusercontent.com/assets/3143027/17549874/b1012166-5ef2-11e6-9d9b-068a8bdb62fc.png)
In this image you see that the point (0,0) is transformed to (100,0).

I didn't show the images for the Y transformation. But there is the same problem like the X transformation.

The work-around is very dangerous. If someone else is reading my code the other programmer could think that it is wrong and switch the source and target points back.

Greetings,
Thomas