1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
  | 
#include "opencv2/opencv.hpp"
#include <algorithm>
cv::Mat src_img;
cv::Mat lut_img;
int slider_intensity = 0;
int radius = 100;
bool leftdown = false;
cv::Point start = cv::Point(-1, -1);
cv::Point end = cv::Point(-1, -1);
cv::Point Liquefy(const cv::Point& c, const cv::Point& m, const cv::Point& x, const float r)
{
    auto DistancePow = [](const cv::Point2f& p1, const cv::Point2f& p2){
        return std::pow(p1.x - p2.x, 2) +  std::pow(p1.y - p2.y, 2);
    };
    cv::Point u = cv::Point(-1, -1);
    cv::Point2f direction = m - c;
    double factor = 0.2 * std::pow((r * r - DistancePow(x, c)) / (r * r - DistancePow(x, c) + DistancePow(m, c) ), 2);
    u = x - cv::Point(factor * direction.x, factor * direction.y);
    return u;
}
void Reshape(const cv::Mat& src, const cv::Point& start, const cv::Point& end, const float radius, cv::Mat& result)
{
    if(src.empty()){ return;}
    result = src.clone();
    int rows = src.rows;
    int cols = src.cols;
    auto Distance = [](const cv::Point2f& p1, const cv::Point2f& p2){
        return std::sqrt(std::pow(p1.x - p2.x, 2) +  std::pow(p1.y - p2.y, 2));
    };
    for(int r = 1; r < rows - 1; r++)
    {
        for(int c = 1; c < cols - 1; c++)
        {
            cv::Point2f p = cv::Point2f(c, r);
            cv::Point2f rp = p;
            if(Distance(p, start) < radius)
            {
                rp = Liquefy(start, end, p, radius);
            }
            result.at<cv::Vec3b>(p) = 0.4 * src.at<cv::Vec3b>(rp)
                    + 0.15 *  src.at<cv::Vec3b>(cv::Point2f(rp.x , rp.y -1) ) + 0.15 *  src.at<cv::Vec3b>(cv::Point2f(rp.x -1, rp.y))
                    + 0.15 *  src.at<cv::Vec3b>(cv::Point2f(rp.x + 1, rp.y) )+ 0.15 *  src.at<cv::Vec3b>(cv::Point2f(rp.x, rp.y + 1)) ;
        }
    }
}
void LutTrack(int, void*)
{
    //无需处理
    std::cout << "radius: "<< radius << std::endl;
}
void OnMouse(int event, int x, int y, int  flag, void* usrdata)
{
    if(event == cv::EVENT_LBUTTONDOWN)
    {
        start = cv::Point(x, y);
        std::cout << "start: "<< x << "," << y << std::endl;
        cv::Mat tmp = src_img.clone();
        cv::circle(tmp, start, 2, cv::Scalar(0, 255, 0));
        cv::circle(tmp, start, radius, cv::Scalar(0, 255, 0));
        leftdown = true;
        cv::imshow("liquefy", tmp);
    }
    if(flag == cv::EVENT_FLAG_LBUTTON)
    {
        cv::Point current = cv::Point(x,y);
        std::cout << "current: "<< x << "," << y << std::endl;
        cv::Mat tmp = src_img.clone();
        cv::circle(tmp, start, 2, cv::Scalar(0, 255, 0));
        cv::circle(tmp, start, radius, cv::Scalar(0, 255, 0));
        cv::line(tmp, start, current, cv::Scalar(0, 255, 0));
        cv::imshow("liquefy", tmp);
    }
    if(event == cv::EVENT_LBUTTONUP)
    {
        if(leftdown)
        {
            leftdown = false;
            cv::Point end = cv::Point(x,y);
            cv::Mat result;
            Reshape(src_img, start, end, radius, result);
            src_img = result;
            cv::imshow("liquefy", result);
        }
    }
}
int main(int argc, char** argv)
{
    src_img = cv::imread("/Volumes/HaoMingSSD/Learnning/effect/data/img/lut/1.jpg");
    if(src_img.empty()) {return -1;}
    cv::namedWindow("liquefy");
    cv::setMouseCallback("liquefy", OnMouse, nullptr);
    //cv::createTrackbar("radius", "liquefy", &radius, 100, LutTrack, nullptr);
    //LutTrack(0, nullptr);
    cv::imshow("liquefy", src_img);
    cv::waitKey(0);
    return 0;
}
  |