5

I want to draw curve on control points so that I can move the curve to change the colours , below is the code , getting help from a very well explained answer

const int N=5;      // number of control points (must be >= 4)
float ctrl[N]=      // control points y values initiated with linear function y=x
{           // x value is index*1.0/(N-1)
    0.00,
    0.25,
    0.50,
    0.75,
    1.00,
 };
float correction(float col,float *ctrl,int n)
    {
    float di=1.0/float(n-1);
    int i0,i1,i2,i3;
    float t,tt,ttt;
    float a0,a1,a2,a3,d1,d2;
    // find start control point
    col*=float(n-1);
    i1=col; col-=i1;
    i0=i1-1;
    i2=i1+1; if (i2>=n) i2=n-1;
    i3=i1+2;
    // compute interpolation coefficients
    if (i0>=0) d1=0.5*(ctrl[i2]-ctrl[i0]); else d1=ctrl[i2]-ctrl[i1];
    if (i3< n) d2=0.5*(ctrl[i3]-ctrl[i1]); else d2=ctrl[i2]-ctrl[i1];
    a0=ctrl[i1];
    a1=d1;
    a2=(3.0*(ctrl[i2]-ctrl[i1]))-(2.0*d1)-d2;
    a3=d1+d2+(2.0*(-ctrl[i2]+ctrl[i1]));
    // now interpolate new colro intensity
    t=col; tt=t*t; ttt=tt*t;
    t=a0+(a1*t)+(a2*tt)+(a3*ttt);
    return t;
    }




int main (int argc, const char** argv)
{
Mat input = imread ("E:\\img2.jpg");
Mat input1 = input;
for(int i=0 ; i<input1.rows ; i++)
{
    for (int p=0;p<input1.cols;p++)
    {

        input1.at<cv::Vec3b>(i,p)[0] = 255*correction(input1.at<cv::Vec3b>(i,p)[0]/255.0,ctrl,N);  //B
        input1.at<cv::Vec3b>(i,p)[1] = 255*correction(input1.at<cv::Vec3b>(i,p)[1]/255.0,ctrl,N);  //G
        input1.at<cv::Vec3b>(i,p)[2] = 255*correction(input1.at<cv::Vec3b>(i,p)[2]/255.0,ctrl,N);  //R

    }
}

imshow("image" , input);
waitKey();

}

But the required output is like the curve the program is working , but the curves are not drawing on my screen like below , how to draw them using opencv or other approach So that these lines can play the role of their specific colour in image and with their values , like below right one is the orignal image and left one is the result of changing values through cuves , below curves are the control points per B,G,R

enter image description here

Community
  • 1
  • 1
AHF
  • 1,070
  • 2
  • 15
  • 47
  • Okay. What is your actual question? Is there something wrong with the curves? Are they not smooth enough (you might want to increase the number of control points for that). – Froyo May 14 '14 at 05:58
  • no , actual question is that the program is working , but the curves are not drawing on my screen , how to draw them using opencv or other approach – AHF May 14 '14 at 08:40
  • hmm. but we do see curves there, no ? how did you draw those ? – berak May 14 '14 at 08:44
  • that's not drawn by me :( , that was from other question , that man which I linked above uses other tool – AHF May 14 '14 at 08:47
  • he uses `Simple for (t=0;t<=1;t+=0.01) loop with Canvas->LineTo(t,correction(t,ctrl,5));` but i saw only `createTrackbar` in opencv – AHF May 14 '14 at 08:49

1 Answers1

12

This code sketch allows you to edit spline with mouse it uses the files from this link (attach to your project: overhauser.cpp overhauser.hpp and vec3.hpp):

Left mouse button adds/moves a point, right removes.

enter image description here

#include <iostream>
#include <vector>
#include <stdio.h>
#include <functional>
#include <algorithm>
#include <numeric>
#include <cstddef>
#include "opencv2/opencv.hpp"
#include <iostream>
#include <fstream>
#include "overhauser.hpp"

using namespace std;
using namespace cv;

Mat result;
Mat Img;

int current_color=0;

vector<cv::Point2f> pts_red;
vector<cv::Point2f> pts_green;
vector<cv::Point2f> pts_blue;

Mat curvesImg;
int selectedPt=-1;

CRSpline* spline_red = 0;
CRSpline* spline_green = 0;
CRSpline* spline_blue = 0;

unsigned char LUT_RED[256];
unsigned char LUT_GREEN[256];
unsigned char LUT_BLUE[256];

// comparison function:
bool mycomp (Point2f p1, Point2f p2)
{
    return p1.x<p2.x;
}

float dist(Point2f p1,Point2f p2)
{
    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

int findNEarestPt(Point2f pt, float maxDist)
{   
    vector<Point2f> current_pts_set;

    current_color=0;

    if(pt.x>255 && pt.x<512)
    {
        current_color=1;
    }

    if(pt.x>=512)
    {
        current_color=2;
    }

    float ptx=pt.x;

    switch(current_color)
    {
    case 0:
        current_pts_set=pts_red;
        break;
    case 1:
        current_pts_set=pts_green;
        pt.x-=255;
        break;
    case 2:
        current_pts_set=pts_blue;
        pt.x-=511;
        break;
    }

    float minDist=FLT_MAX;
    int ind=-1;
    for(int i=0;i<current_pts_set.size();++i)
    {
        float d=dist(pt,current_pts_set[i]);
        if(minDist>d)
        {
            ind=i;
            minDist=d;
        }
    }
    if(minDist>maxDist)
    {
        ind=-1;
    }

    return ind;
}

float F(float t,float x, CRSpline* spline)
{
    vec3 rv = spline->GetInterpolatedSplinePoint(t);
    return x-rv.x;
}

float solveForX(float x,CRSpline* slpine)
{
    float a=-1.0f,b=1.0,c,e=1e-2;
    c=(a+b)/2;
    while( (fabs(b-a)>e) && (F(c,x,slpine)!=0) )
    {
        if (F(a,x,slpine)*F(c,x,slpine)<0)
        {
            b=c;
        }
        else
        {
            a=c;
        }
        c=(a+b)/2;
    }
    return c;
}


int ind=-1;

void mouseHandler(int event, int x, int y, int flags, void* param)
{
    Point2f m;
    m.x=x;
    m.y=y;
    curvesImg=Scalar(0,0,0);

    switch (event)
    {
    case cv::EVENT_RBUTTONDOWN:
        ind=findNEarestPt(m,5);
        if (ind==-1)
        {

        }else
        {
            switch(current_color)
            {
            case 0:
                pts_red.erase(pts_red.begin()+ind);
                break;
            case 1:
                pts_green.erase(pts_green.begin()+ind);
                break;
            case 2:
                pts_blue.erase(pts_blue.begin()+ind);
                break;
            }
            ind=-1;
        }
        break;

    case cv::EVENT_LBUTTONDOWN:
        ind=findNEarestPt(m,5);
        if (ind==-1)
        {
            switch(current_color)
            {
            case 0:
                pts_red.push_back(m);
                selectedPt=pts_red.size()-1;
                break;
            case 1:

                pts_green.push_back(Point2f(m.x-255.0,m.y));
                selectedPt=pts_green.size()-1;
                break;
            case 2:
                pts_blue.push_back(Point2f(m.x-511,m.y));
                selectedPt=pts_blue.size()-1;
                break;
            }
        }else
        {
            selectedPt=ind;
        }
        break;

    case cv::EVENT_MOUSEMOVE:
        if(ind!=-1)
        {
            switch(current_color)
            {
            case 0:
                pts_red[selectedPt].x=m.x;
                pts_red[selectedPt].y=m.y;
                break;
            case 1:
                pts_green[selectedPt].x=m.x-255;
                pts_green[selectedPt].y=m.y;
                break;
            case 2:
                pts_blue[selectedPt].x=m.x-511;
                pts_blue[selectedPt].y=m.y;
                break;
            }
        }
        break;
    case cv::EVENT_LBUTTONUP:
        ind=-1;
        break;
    }

    std::sort(pts_red.begin(),pts_red.end(),mycomp);
    if(pts_red.size()>0)
    {
        pts_red[pts_red.size()-1].x=255;
        pts_red[0].x=0;
    }

    std::sort(pts_green.begin(),pts_green.end(),mycomp);
    if(pts_green.size()>0)
    {
        pts_green[pts_green.size()-1].x=255;
        pts_green[0].x=0;
    }

    std::sort(pts_blue.begin(),pts_blue.end(),mycomp);
    if(pts_blue.size()>0)
    {
        pts_blue[pts_blue.size()-1].x=255;
        pts_blue[0].x=0;
    }

    for(int i=0;i<pts_red.size();++i)
    {
        circle(curvesImg,pts_red[i],5,Scalar(0,0,255),-1,CV_AA);
    }

    for(int i=0;i<pts_green.size();++i)
    {
        circle(curvesImg,Point2f(pts_green[i].x+255,pts_green[i].y),5,Scalar(0,255,0),-1,CV_AA);
    }

    for(int i=0;i<pts_blue.size();++i)
    {
        circle(curvesImg,Point2f(pts_blue[i].x+511,pts_blue[i].y),5,Scalar(255,0,0),-1,CV_AA);
    }

    if (spline_red) {delete spline_red;}
    spline_red = new CRSpline();

    if (spline_green) {delete spline_green;}
    spline_green = new CRSpline();

    if (spline_blue) {delete spline_blue;}
    spline_blue = new CRSpline();

    for (int i=0;i<pts_red.size();++i)
    {
        vec3 v(pts_red[i].x,pts_red[i].y,0);
        spline_red->AddSplinePoint(v);
    }

    for (int i=0;i<pts_green.size();++i)
    {
        vec3 v(pts_green[i].x,pts_green[i].y,0);
        spline_green->AddSplinePoint(v);
    }

    for (int i=0;i<pts_blue.size();++i)
    {
        vec3 v(pts_blue[i].x,pts_blue[i].y,0);
        spline_blue->AddSplinePoint(v);
    }

    vec3 rv_last(0,0,0);
    if(pts_red.size()>2)
    {
        for(int i=0;i<256;++i)
        {
            float t=solveForX(i,spline_red);
            vec3 rv = spline_red->GetInterpolatedSplinePoint(t);
            if(rv.y>255){rv.y=255;}
            if(rv.y<0){rv.y=0;}
            unsigned char I=(unsigned char)(rv.y);
            LUT_RED[i]=255-I;
            if(i>0)
            {
                line(curvesImg,Point(rv.x,rv.y),Point(rv_last.x,rv_last.y),Scalar(0,0,255),1);
            }
            rv_last=rv;
        }
    }
    rv_last=vec3(0,0,0);
    if(pts_green.size()>2)
    {
        for(int i=0;i<256;++i)
        {
            float t=solveForX(i,spline_green);
            vec3 rv = spline_green->GetInterpolatedSplinePoint(t);
            if(rv.y>255){rv.y=255;}
            if(rv.y<0){rv.y=0;}
            unsigned char I=(unsigned char)(rv.y);
            LUT_GREEN[i]=255-I;
            if(i>0)
            {
                line(curvesImg,Point(rv.x+255,rv.y),Point(rv_last.x+255,rv_last.y),Scalar(0,255,0),1);
            }
            rv_last=rv;
        }
    }
    rv_last=vec3(0,0,0);
    if(pts_blue.size()>2)
    {
        for(int i=0;i<256;++i)
        {
            float t=solveForX(i,spline_blue);
            vec3 rv = spline_blue->GetInterpolatedSplinePoint(t);
            if(rv.y>255){rv.y=255;}
            if(rv.y<0){rv.y=0;}
            unsigned char I=(unsigned char)(rv.y);
            LUT_BLUE[i]=255-I;
            if(i>0)
            {
                line(curvesImg,Point(rv.x+511,rv.y),Point(rv_last.x+511,rv_last.y),Scalar(255,0,0),1);
            }
            rv_last=rv;
        }

    }

    int cur_col=0;

    if(m.x>255 && m.x<512)
    {
        cur_col=1;
    }

    if(m.x>=512)
    {
        cur_col=2;
    }

    Scalar col;
    switch(cur_col)
    {
    case 0:
        col=Scalar(0,0,255);
        break;
    case 1:
        col=Scalar(0,255,0);
        break;
    case 2:
        col=Scalar(255,0,0);
        break;
    }
    line(curvesImg,Point(0,m.y),Point(curvesImg.cols,m.y),col,1);
    line(curvesImg,Point(m.x,0),Point(m.x,curvesImg.rows),col,1);

    imshow("Correction curves",curvesImg);  

    vector<Mat> ch;
    cv::split(Img,ch);
    LUT(ch[0],Mat(256,1,CV_8UC1,LUT_BLUE),ch[0]);
    LUT(ch[2],Mat(256,1,CV_8UC1,LUT_RED),ch[2]);
    LUT(ch[1],Mat(256,1,CV_8UC1,LUT_GREEN),ch[1]);
    cv::merge(ch,result);

    imshow("Transformed",result);   
}
// ---------------------------------
// 
// ---------------------------------
//==============================================================================

int main( int argc, char** argv )
{

    for (int i=0;i<256;++i)
    {
        LUT_RED[i]=i;
        LUT_GREEN[i]=i;
        LUT_BLUE[i]=i;
    }

    namedWindow("Image");
    namedWindow("Correction curves");
    namedWindow("Transformed");

    Img=imread("D:\\ImagesForTest\\lena.jpg",1);

    imshow("Image",Img);

    curvesImg=Mat::zeros(256,768,CV_8UC3);
    setMouseCallback("Correction curves", mouseHandler, NULL);
    waitKey(0);

    getchar();
}
Andrey Smorodov
  • 10,649
  • 2
  • 35
  • 42
  • berak i know you will :P , i guess it before your vote – AHF May 14 '14 at 16:12
  • Thanks :). It seems that I should swap x and y axis. – Andrey Smorodov May 14 '14 at 16:21
  • @AndreySmorodov which is the best way to follow to get a strong hold on color ? the way i follow above in question is the cubic and your one is the Catmull-Rom ? – AHF May 14 '14 at 16:27
  • The spline (or may be linear regression for instance), or other approxination function just an instrument for changing color distribution (set LUT). They are approximately the same. The choice usually made by usage convenience parameter. For aceive some result (strong hold on color for instance) you need to formulate cost function that will estimate goodness of result for parameters (control point coordinates on our case) you've set. Then just optimize the cost funtion WRT parameters, and you'll get that you want. – Andrey Smorodov May 14 '14 at 16:37
  • I've corrected the code again (added simple solver for x from parameter t). Now it seems works correct. – Andrey Smorodov May 14 '14 at 17:13
  • Control points stored in pts vector. You can read them from it. As alternative you can save LUT table for next image transformation. – Andrey Smorodov May 14 '14 at 19:03
  • 1
    The thing i am saying is look in your resultant image , there are two shape , one is original (without red) and one which is following the curves and colored , so if i have the right one image (without red) and i want to convert it into left one (red coloured) with curves once but when i get it through curve,i want to save that values of curve and then next time i only multiply that value with the image to get the resultant image without drawing curves,like we did for sepia filter we multiply .131,.534,.272, .168,.686,.349, .189,.769,.393; these values with original image we wil get sepia – AHF May 15 '14 at 16:25
  • Not multiply, but apply lookup table transform. That means you get pixel value (say val=120), then get new value from LUT table (say val_new=Lut[val]) and put new value to the pixel position. For save transformation rule you need to save the LUT values. – Andrey Smorodov May 15 '14 at 18:36
  • when i am converting that `Result` window which is `Red` in your case , into 3 independent windows in case of independent `R` independent `G` and independent `B` , that when i perform the task on R it didnt effect green and blue and when i performed red it remain on the image and after that when apply other it carry on from it , i did this approximately , but the problem is when i move the cursor on `Red` window it also move on other 2 , and when i put other mouse move calls it give error that its already declared – AHF May 16 '14 at 14:13
  • 1
    Ough :) Just replicate it 3 times :). I've made it for you. – Andrey Smorodov May 16 '14 at 16:04
  • @AndreySmorodov If when i move the curves and got the resultant image now i want that my program save that values of curves and i can display the same image without that curves but with directly from values, is it possible ? – AHF Jul 20 '14 at 12:44
  • Yes, just save LUT tables. And apply them to your new images. – Andrey Smorodov Jul 21 '14 at 06:22
  • Value of tables from `if(pts_red.size()>2)` ( same like for `green and blue ` ) from here or from main ? because i tried of main , its not working – AHF Jul 23 '14 at 19:02
  • LUT_RED, LUT_GREEN and LUT_BLUE – Andrey Smorodov Jul 23 '14 at 21:40