Click here to Skip to main content
15,868,141 members
Articles / Multimedia / GDI+

Cubic Bezier Spline Curves and Image Curve Adjustment

Rate me:
Please Sign up or sign in to vote.
5.00/5 (13 votes)
12 May 2009CPOL2 min read 60.7K   2.4K   25   6
Cubic Bezier Spline Curves constructed and used in Image Curve adjustment
Image 1

Introduction

This program is my second image editing tool --- Image Curve Adjustment. The first one is Free Image Transformation. This image tool includes two user controls, ImageCurve and Canvas. The control ImageCurve had been written before (Link). But they are totally different. The old one is based on the quadratic Bezier curve, but this new one is based on Cubic Bezier Spline and works more like Photoshop.

Cubic Bezier Spline

We know C# provides the method DrawCurve to draw curves, but we can't get coordinates of points on the curve drawn by DrawCurve. We have to construct a curve by ourselves for adjusting the image curve.

An easy way of making a controlled-design curve with many control points is to use Bezier spline curves. To specify a cubic Bezier curve, we need four control points P0, P1, P2, P3, and the curve is given by:

P(t)=(1-t)<sup>3</sup>P<sub>0</sub>+3(1-t)<sup>2</sup>tP<sub>1</sub>+3(1-t)t<sup>2</sup>P<sub>2</sub>+t<sup>3</sup>P<sub>3</sub>, for 0<=t<1 

Points P0 and P3 are on the curve, but P1, P2 usually are not on the curve. So we have to compute the control points from the data points for the individual pieces. For a mathematical background, please read this paper.

To get control points, first we made the augmented matrix [M|C] then row reduced completely to [I|P]:

C#
private void getControlPoints()
{
    if (dataPoint != null && dataPoint.Length == 3)
    {
        controlPoint = new Vector[3];
        controlPoint[0] = dataPoint[0];
        controlPoint[1] =(6 * dataPoint[1] - dataPoint[0] - dataPoint[2])/4;
        controlPoint[2] = dataPoint[2];
    }
    if (dataPoint!=null && dataPoint.Length> 3)
    {
        int n = dataPoint.Length;
        controlPoint = new Vector[n];
        double[] diag = new double[n]; 	// tridiagonal matrix a(i , i)
        double[] sub = new double[n]; 	// tridiagonal matrix a(i , i-1)
        double[] sup = new double[n]; 	// tridiagonal matrix a(i , i+1)
         for (int i = 0; i < n; i++)
        {
            controlPoint[i] = dataPoint[i];
            diag[i] = 4;
            sub[i] = 1;
            sup[i] = 1;
        }
        controlPoint[1] = 6 * controlPoint[1] - controlPoint[0];
        controlPoint[n - 2] = 6 * controlPoint[n - 2] - controlPoint[n - 1];
        for (int i = 2; i < n - 2; i++)
        {
            controlPoint[i] = 6 * controlPoint[i];
        }
         // Gaussian elimination from row 1 to n-2
        for (int i = 2; i < n - 1; i++)
        {
            sub[i] = sub[i] / diag[i - 1];
            diag[i] = diag[i] - sub[i] * sup[i - 1];
            controlPoint[i] = controlPoint[i] - sub[i] * controlPoint[i - 1];
        }
         controlPoint[n - 2] = controlPoint[n - 2] / diag[n - 2];
         for (int i = n - 3; i >0; i--)
        {
            controlPoint[i] = (controlPoint[i] - sup[i] * controlPoint[i + 1]) / diag[i];
        }
    }

We can use the function P(t)=(1-t)3P0+3(1-t) 2tP1+3(1-t)t2P2+t3P3 to get the spline once we know the control points, the t is based on the precision of axis:

C#
for (int i = 0; i < controlPoint.Length - 1; i++)
{
    Vector b1 = controlPoint[i] * 2.0 / 3.0 + controlPoint[i + 1] / 3.0;
    Vector b2 = controlPoint[i] / 3.0 + controlPoint[i + 1] * 2.0 / 3.0;
     int n = 1;
    if(isXcalibrated)
        n=(int)((dataPoint[i + 1].X - dataPoint[i].X) / precision);
    else n = (int)((dataPoint[i + 1].Y - dataPoint[i].Y) / precision);
    if (n == 0) n = 1;
    if (n < 0) n = -n;
    for (int j = 0; j < n; j++ )
    {
        double t = (double)j / (double)n;
        Vector v = (1 - t) * (1 - t) * (1 - t) * dataPoint[i] + 
		3 * (1 - t) * (1 - t) * t * b1 +
            3 * (1 - t) * t * t * b2 + t * t * t * dataPoint[i + 1];
        splinePoint.Add(v);
    }
}

In this program, the t is based on x-axis precision. For drawing spline curves on screen, I set t = 5...

C#
YLScsDrawing.Geometry.Spline spline = new YLScsDrawing.Geometry.Spline();
        spline.ListDataPoint = keyPt;
        spline.Precision = 5;
        Point[] splinePt=spline.SplinePoint;
        g.DrawLines(new Pen(Color.Black), splinePt);
        g.DrawLine(new Pen(Color.Black), keyPt[keyPt.Count - 1], 
					splinePt[splinePt.Length - 1]);

and I set t = 1 for getting image level:

C#
YLScsDrawing.Geometry.Spline sp = new YLScsDrawing.Geometry.Spline();
        sp.DataPoint = pts;
        sp.Precision = 1.0;
        Point[] spt=sp.SplinePoint;
        for (int i = 0; i < spt.Length; i++)
        {
            int n = spt[i].Y;
            if (n < 0) n = 0;
            if (n > 255) n = 255;
            level[pts[0].X + i] = (byte)n;
        }

Control ImageCurve

After construction of the cubic Bezier spline, we can specify a curve to edit image colors, its X axis as the image input level and Y axis as the image output level. That is the new user control ImageCurve.

This control can let the user add the curve's control point:

C#
for (int i = 1; i < keyPt.Count; i++)
        {
            if (e.X > keyPt[i-1].X+20 && e.Y > 0 && 
			e.X < keyPt[i].X-20 && e.Y < this.Height)
            {
                keyPt.Insert(i, e.Location); // add a point
                drag = true;
                moveflag = i;
                this.Cursor = Cursors.Hand;
                Invalidate();
            }
        }	

It can also let the user remove the curve's control point:

C#
if (drag && moveflag > 0 && moveflag < keyPt.Count - 1)
        {
            if (e.X > keyPt[moveflag - 1].X + 20 && e.X < keyPt[moveflag + 1].X - 20)
            {
                keyPt[moveflag] = e.Location;
            }
            else
            {
                keyPt.RemoveAt(moveflag); // remove a point
                drag = false;
            }
        }	

It works like PhotoShop.

Control Canvas

The last one I'll introduce here is the control Canvas. It looks like PictureBox. But it is zoomable and scrollable, and always keeps the picture in the center. It is another Zoomable and Scrollable PictureBox that I wrote a year ago. Hope you like both.

Thanks

Thanks for trying this program. Any suggestion will be much appreciated.

History

  • May 12, 2009: First posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Unknown
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionimage processing Pin
elham mohammed16-Jun-21 9:58
elham mohammed16-Jun-21 9:58 
Questionask question: how does the getControlPoints function works Pin
luluio200029-Nov-12 21:19
luluio200029-Nov-12 21:19 
QuestionGaussian elimination Pin
KiTann26-Apr-12 19:46
KiTann26-Apr-12 19:46 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey20-Feb-12 19:55
professionalManoj Kumar Choubey20-Feb-12 19:55 
GeneralThanks! Pin
Member 24770538-Dec-09 22:36
Member 24770538-Dec-09 22:36 
Generalvery interesting Pin
Jeff Circeo13-May-09 4:53
Jeff Circeo13-May-09 4:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.