[Insight-developers] To draw a cross or a circle on image
Paul Koshevoy
koshevoy at sci.utah.edu
Tue May 23 13:14:32 EDT 2006
I've attached the code for drawing anti-aliased lines on a 2D ITK image.
You can use that to draw a circle.
Paul.
Paul Koshevoy wrote:
> Alan wrote:
>
>> Hi folks !
>>
>> Is there a way to draw a cross or a circle on an image ?
>> Are there any primitives to do it ?
>> Thanks for any hints.
>>
>> Alan
>> _______________________________________________
>> Insight-developers mailing list
>> Insight-developers at itk.org
>> http://www.itk.org/mailman/listinfo/insight-developers
>>
>>
> Here is some sample code to draw crosses:
>
>
> //----------------------------------------------------------------
> // p2x1_t
> //
> typedef itk::Point<double, 2> p2x1_t;
>
> //----------------------------------------------------------------
> // v2x1_t
> //
> typedef itk::Vector<double, 2> v2x1_t;
>
> //----------------------------------------------------------------
> // mark
> //
> template <class image_t>
> void
> mark(typename image_t::Pointer & image,
> const typename image_t::IndexType & index,
> const typename image_t::PixelType & mark_value,
> const int arm_length = 2,
> const char symbol = '+')
> {
> typedef typename image_t::SpacingType spacing_t;
> typedef typename image_t::RegionType::SizeType image_size_t;
> typedef typename image_t::IndexType index_t;
>
> // calculate image bounding box:
> spacing_t sp = image->GetSpacing();
> image_size_t sz = image->GetLargestPossibleRegion().GetSize();
> p2x1_t min = image->GetOrigin();
> p2x1_t max = min + v2x1(sp[0] * double(sz[0] - 1),
> sp[1] * double(sz[1] - 1));
>
> index_t xy;
> for (int j = -arm_length; j <= arm_length; j++)
> {
> int x = index[0] + j;
> int y = index[1] + j;
>
> if (symbol == '+')
> {
> // draw a cross:
> xy[0] = x;
> xy[1] = index[1];
> if (xy[0] >= 0 && xy[0] < sz[0] &&
> xy[1] >= 0 && xy[1] < sz[1])
> {
> image->SetPixel(xy, mark_value);
> }
>
> xy[0] = index[0];
> xy[1] = y;
> if (xy[0] >= 0 && xy[0] < sz[0] &&
> xy[1] >= 0 && xy[1] < sz[1])
> {
> image->SetPixel(xy, mark_value);
> }
> }
> else
> {
> // draw a diagonal cross:
> xy[0] = x;
> xy[1] = y;
> if (xy[0] >= 0 && xy[0] < sz[0] &&
> xy[1] >= 0 && xy[1] < sz[1])
> {
> image->SetPixel(xy, mark_value);
> }
>
> xy[1] = index[1] - j;
> if (xy[0] >= 0 && xy[0] < sz[0] &&
> xy[1] >= 0 && xy[1] < sz[1])
> {
> image->SetPixel(xy, mark_value);
> }
> }
> }
> }
>
> //----------------------------------------------------------------
> // mark
> //
> template <class image_t>
> void
> mark(typename image_t::Pointer & image,
> const p2x1_t & mark_coords,
> const typename image_t::PixelType & mark_value,
> const int arm_length = 2,
> const char symbol = '+')
> {
> typedef typename image_t::IndexType index_t;
>
> index_t index;
> if (!image->TransformPhysicalPointToIndex(mark_coords, index))
> {
> // the mark lays outside of the image:
> return;
> }
>
> mark<image_t>(image, index, mark_value, arm_length, symbol);
> }
>
> _______________________________________________
> Insight-developers mailing list
> Insight-developers at itk.org
> http://www.itk.org/mailman/listinfo/insight-developers
>
-------------- next part --------------
#ifndef DRAW_HXX_
#define DRAW_HXX_
// system includes:
#include <algorithm>
// ITK includes:
#include <itkImage.h>
namespace wu
{
//----------------------------------------------------------------
// ipart
//
// return integer part of x
inline double ipart(const double & x)
{
return (x == x) ? x - fmod(x, 1.0) : x;
}
//----------------------------------------------------------------
// round
//
inline double round(const double & x)
{
return ipart(x + 0.5);
}
//----------------------------------------------------------------
// fpart
//
// return fractional part of x
inline double fpart(const double & x)
{
return x - ipart(x);
}
//----------------------------------------------------------------
// rfpart
//
inline double rfpart(const double & x)
{
return 1.0 - fpart(x);
}
//----------------------------------------------------------------
// plot_pixel
//
template <class image_t>
void
plot_pixel(typename image_t::Pointer & image,
const unsigned int & width,
const unsigned int & height,
const typename image_t::IndexType & index,
const double & w,
const double & c)
{
if (index[0] >= width || index[1] >= height) return;
typedef typename image_t::PixelType color_t;
double o = double(image->GetPixel(index));
double n = (1.0 - w) * o + w * c;
n = std::max(0.0, std::min(255.0, n));
image->SetPixel(index, color_t(n));
}
//----------------------------------------------------------------
// plot_normal
//
template <class image_t>
void
plot_normal(typename image_t::Pointer & image,
const unsigned int & width,
const unsigned int & height,
const double & x,
const double & y,
const double & w,
const double & c)
{
typename image_t::IndexType index;
index[0] = (unsigned int)(x);
index[1] = (unsigned int)(y);
plot_pixel<image_t>(image, width, height, index, w, c);
}
//----------------------------------------------------------------
// plot_swapped
//
template <class image_t>
void
plot_swapped(typename image_t::Pointer & image,
const unsigned int & width,
const unsigned int & height,
const double & x,
const double & y,
const double & w,
const double & c)
{
typename image_t::IndexType index;
index[0] = (unsigned int)(y);
index[1] = (unsigned int)(x);
plot_pixel<image_t>(image, width, height, index, w, c);
}
//----------------------------------------------------------------
// draw_nearly_horizontal_line
//
// Xiaolin Wu's line algorithm taken from the wikipedia article
// http://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm
//
template <class image_t>
void
draw_nearly_horizontal_line
(typename image_t::Pointer & image,
const double & c,
double x1,
double y1,
double x2,
double y2,
void(*draw_pixel)(typename image_t::Pointer &, // image
const unsigned int &, // width
const unsigned int &, // height
const double &, // x
const double &, // y
const double &, // weight
const double &)) // paint color
{
typename image_t::SizeType sz =
image->GetLargestPossibleRegion().GetSize();
// check that x1 < x2
if (x2 < x1)
{
std::swap(x1, x2);
std::swap(y1, y2);
}
double dx = x2 - x1;
double dy = y2 - y1;
double gradient = dy / dx;
// handle first endpoint
double xend = round(x1);
double yend = y1 + gradient * (xend - x1);
double xgap = rfpart(x1 + 0.5);
double xpxl1 = xend; // this will be used in the main loop
double ypxl1 = ipart(yend);
draw_pixel(image, sz[0], sz[1], xpxl1, ypxl1, rfpart(yend) * xgap, c);
draw_pixel(image, sz[0], sz[1], xpxl1, ypxl1 + 1, fpart(yend) * xgap, c);
double intery = yend + gradient; // first y-intersection for the main loop
// handle second endpoint
xend = round(x2);
yend = y2 + gradient * (xend - x2);
xgap = rfpart(x2 - 0.5);
double xpxl2 = xend; // this will be used in the main loop
double ypxl2 = ipart(yend);
draw_pixel(image, sz[0], sz[1], xpxl2, ypxl2, rfpart(yend) * xgap, c);
draw_pixel(image, sz[0], sz[1], xpxl2, ypxl2 + 1, fpart(yend) * xgap, c);
// main loop
for (double x = xpxl1 + 1.0; x <= xpxl2 - 1.0; x += 1.0)
{
draw_pixel(image, sz[0], sz[1], x, ipart(intery), rfpart(intery), c);
draw_pixel(image, sz[0], sz[1], x, ipart(intery) + 1, fpart(intery), c);
intery = intery + gradient;
}
}
}
//----------------------------------------------------------------
// draw_line
//
template <class image_t>
void
draw_line(typename image_t::Pointer & image,
const typename image_t::PixelType color,
double x1,
double y1,
double x2,
double y2)
{
if (false)
{
// MSVC++ will not instantiate plot_normal and plot_swapped
// unless it sees them called explicitly:
wu::plot_normal<image_t>(image, 0, 0, 0.0, 0.0, 0.0, 0.0);
wu::plot_swapped<image_t>(image, 0, 0, 0.0, 0.0, 0.0, 0.0);
}
double dx = fabs(x2 - x1);
double dy = fabs(y2 - y1);
typename image_t::PointType origin = image->GetOrigin();
typename image_t::SpacingType spacing = image->GetSpacing();
x1 /= spacing[0];
x2 /= spacing[0];
y1 /= spacing[1];
y2 /= spacing[1];
if (dx > dy)
{
// horizontal line:
wu::draw_nearly_horizontal_line<image_t>(image,
double(color),
x1, y1, x2, y2,
wu::plot_normal<image_t>);
}
else if (dy != 0.0)
{
// vertical line:
wu::draw_nearly_horizontal_line<image_t>(image,
double(color),
y1, x1, y2, x2,
wu::plot_swapped<image_t>);
}
}
//----------------------------------------------------------------
// draw_line_rotated
//
template <class image_t>
void
draw_line_rotated(typename image_t::Pointer & image,
const typename image_t::PixelType color,
const double & x1,
const double & y1,
const double & x2,
const double & y2,
const double & radians,
const double & ox = 0.0,
const double & oy = 0.0)
{
const double ct = ::cos(radians);
const double st = ::sin(radians);
const double u1 = ox + ct * (x1 - ox) - st * (y1 - oy);
const double v1 = oy + ct * (y1 - oy) + st * (x1 - ox);
const double u2 = ox + ct * (x2 - ox) - st * (y2 - oy);
const double v2 = oy + ct * (y2 - oy) + st * (x2 - ox);
draw_line<image_t>(image, color, u1, v1, u2, v2);
}
#endif // DRAW_HXX_
More information about the Insight-developers
mailing list