13,295,448 members (57,025 online)
alternative version

#### Stats

40.2K views
22 bookmarked
Posted 12 May 2009

# Cubic Bezier Spline Curves and Image Curve Adjustment

, 12 May 2009
 Rate this:
Cubic Bezier Spline Curves constructed and used in Image Curve adjustment

## 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]:

```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:

```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];
}
}```

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

```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:

```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:

```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:

```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

## Share

 Unknown
No Biography provided

## You may also be interested in...

 Pro

 First Prev Next
 ask question: how does the getControlPoints function works luluio200029-Nov-12 22:19 luluio2000 29-Nov-12 22:19
 Gaussian elimination KiTann26-Apr-12 20:46 KiTann 26-Apr-12 20:46
 My vote of 5 manoj kumar choubey20-Feb-12 20:55 manoj kumar choubey 20-Feb-12 20:55
 Thanks! Member 24770538-Dec-09 23:36 Member 2477053 8-Dec-09 23:36
 very interesting JeffCirceo13-May-09 5:53 JeffCirceo 13-May-09 5:53
 Last Visit: 31-Dec-99 19:00     Last Update: 14-Dec-17 15:35 Refresh 1