Jump to content

Line Drawing


BoltBait

Recommended Posts

  • 3 weeks later...

Your filter does edge detection + binarization. I attached the result of your code without thresholding, and the result of mine.

I didn't publish it yet, but basically it implements the sobel operator ( http://en.wikipedia.org/wiki/Sobel_operator ).

I was wondering how you got that idea of computing some kind of gradients using gaussian blur ? :D

33277_e84cb1a4560f0ef317bd8e5647f999d0

33277_c5931c9148ad8602d86544dd15832fca

Link to comment
Share on other sites

My goal has always been to create an effect that creates a line drawing from a photograph. So, that's why I put the threshold code in. I'm more interested in focusing on the edges and throwing out all other information (gradients/shading).

I was wondering how you got that idea of computing some kind of gradients using gaussian blur ?

The idea for this effect just naturally occured to me when looking at the unsharp mask code that Tanel gave me for my Landscape plugin. I figured that when you Gaussian blur an image, the amount of change a pixel has between the original source canvas and the blured image would show you how likely an edge has been found. I, honestly, didn't know it had a name.

As you can see from my output, I need to really think through how to compute the difference to improve the output. I have a long way to go before it produces good looking results.

BTW, funny, but when I first wrote the effect, it turned out white lines on a black canvas, just like the sample image in the wikipedia article you linked.

Link to comment
Share on other sites

Yes, that's what my code does too, i inverted the output, to make it easier too compare to your output.

Actually, gradients are vectors whos direction indicates the direction of the highest rate of change, and whose magnitude indicates the strength of the changes.

If you set pixel values to the magnitude, you get i picture like mine, but with edge in white.

Your technique detects edges because gaussian blur average colors around one pixel, so if you have a uniform area, the average tends to keep a close value to the original, but if you have an edge, the color is much more affected by different colors surronding it, so when you compute the difference, you can see edges.

Sounds like an esoteric technique, but works :D

I think what you want is a canny edge detector.

It's like a 20y.o. cutting edge edge detector.

First, you apply a gaussian blur to take out high frequency noise. Second then you apply a simple edge detection algo like sobel, or something else. Then you apply one more pass that takes out non maximum edges. Then there's a step called thresholding with hysteris (i didn't try to find out this step, but it can't be so hard, that gets you your binary picture).

http://en.wikipedia.org/wiki/Canny_edge_detector

Link to comment
Share on other sites

Yeah, I'm looking for something that can draw a picture like my avatar from a photograph. Simple, fat lines of uniform size without random stray pixels. The color fills are not necessary. They can be done later by hand.

The "canny edge" effect looks close, but the lines are too thin and the image is too busy.

My closest to date is Ink Sketch (or Ink Sketch followed by a Median blur). But, I'm always looking to improve the output.

Tweeks:

// Author: BoltBait
// Name: Line Drawing
// URL: [url=http://www.BoltBait.com/pdn]http://www.BoltBait.com/pdn[/url]
#region UICode
int Amount1 = 10; // [1,20] Tinker
int Amount2 = 10; // [1,20] Radius
#endregion

// Rick, stop moving stuff around
private byte Clamp2Byte(int iValue)
{
   if (iValue<0) return 0;
   if (iValue>255) return 255;
   return (byte)iValue;
}

unsafe void Render(Surface dst, Surface src, Rectangle rect)
{
   Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();

   // Setup for calling the Blur function
   GaussianBlurEffect blurEffect = new GaussianBlurEffect();
   PropertyCollection bProps = blurEffect.CreatePropertyCollection();
   PropertyBasedEffectConfigToken bParameters = new PropertyBasedEffectConfigToken(bProps);
   bParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount2);
   blurEffect.SetRenderInfo(bParameters, new RenderArgs(dst), new RenderArgs(src));
   // Call the Blur function
   blurEffect.Render(new Rectangle[1] {rect},0,1);

   // Now in the main render loop, the dst canvas has a blurred version of the src canvas
   for (int y = rect.Top; y < rect.Bottom; y++)
   {
       ColorBgra* srcPtr = src.GetPointAddressUnchecked(rect.Left, y);
       ColorBgra* dstPtr = dst.GetPointAddressUnchecked(rect.Left, y);
       for (int x = rect.Left; x < rect.Right; x++)
       {
           ColorBgra AdjustmentPixel = *dstPtr;
           ColorBgra SourcePixel = *srcPtr;

           double RDiff, GDiff, BDiff;
           byte adj;

           // Similar to UnSharp Mask here...
           RDiff = Math.Abs((double)SourcePixel.R - (double)AdjustmentPixel.R) * ((double)Amount1 / 100.0);
           GDiff = Math.Abs((double)SourcePixel.G - (double)AdjustmentPixel.G) * ((double)Amount1 / 100.0);
           BDiff = Math.Abs((double)SourcePixel.B - (double)AdjustmentPixel. * ((double)Amount1 / 100.0);

           // Add up all the differences
           adj = Clamp2Byte((int)(RDiff + GDiff + BDiff));

           // Change the pixel to black or white depending on a threshold amount
           adj = ((adj > Amount1) || (RDiff > (Amount1/3)) || (GDiff > (Amount1/3)) || (BDiff > (Amount1/3)))? (byte)0 : (byte)255;

           AdjustmentPixel.R = AdjustmentPixel.G = AdjustmentPixel.B = adj;

           // I should probably use alpha in the final algorithm, but for for now, just set it to full
           AdjustmentPixel.A = 255;

           // Show it
           *dstPtr = AdjustmentPixel;

           srcPtr++;
           dstPtr++;
       }
   }
}

Link to comment
Share on other sites

I'm looking for something that can draw a picture like my avatar from a photograph. Simple, fat lines of uniform size without random stray pixels. The color fills are not necessary. They can be done later by hand.

I don't know if my different take on this is worth pursuing, but rather than identifying the edges, why not try to identify the spaces in between?

Had I the ability, I'd take the photo and posterize it into lumps of color first then look at the width of the borders in between.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...