Skip to content

Instantly share code, notes, and snippets.

@Novakov
Created March 8, 2013 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Novakov/5117540 to your computer and use it in GitHub Desktop.
Save Novakov/5117540 to your computer and use it in GitHub Desktop.
#pragma once
#include "GDI+ image.h"
typedef boost::gil::bgr8_pixel_t Pixel;
typedef boost::gil::bgr8_view_t View;
typedef boost::gil::bgr8c_view_t ViewReadOnly;
typedef boost::gil::bgr8_view_t::x_iterator Iterator_X;
typedef boost::gil::bgr8_view_t::y_iterator Iterator_Y;
typedef boost::gil::bgr8_view_t::locator Iterator_XY;
/// READ ME FIRST
void TheLookAtMeFakeFunction(View& view, const unsigned short& x, const unsigned short& y)
{
// a View is the access to image's pixels ect.
// pixel access, slow but easy to understand
view(x, y);
view(x, y) = Pixel(0, 0, 255); // blue, green, red channels
// pixel access, optimalize for small x/y increments
Iterator_XY position = view.xy_at(x, y);
*position = Pixel(0, 0, 255);
++position.x(); // point at pixel(x+1, y)
--position.y(); // point at pixel(x, y-1)
// pixel access, row and column interators
unsigned int row_number = 0;
unsigned int column_number = 0;
Iterator_X itr_x = view.row_begin(row_number);
Iterator_Y itr_y = view.col_begin(column_number);
// the Windows applications coordinates system is used in this code
// origin point (0, 0) in the left upper corner
// do not forget: pixel(b,g,r), full_red(0, 0, 255), bright_red(130, 130, 255)
};
////////////////////////////////////////////////////////////////////////////////
// function declarations, draw line
void AntiAliasingDda(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2);
void SymmetricDda(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2);
void Bresenhama(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2);
// function declarations, draw circle
void Circle1Div4(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2);
void MidpointCircle1(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2);
void MidpointCircle2(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2);
// function declarations, draw eliphsis
void Ellipsis(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& a, const unsigned short& b);
// function declarations, flood area
void BoundryFill1Div4(View& view, const unsigned short& x, const unsigned short& y,
const Pixel& fill_color, const Pixel& border_color);
void BoundryFill1Div8(View& view, const unsigned short& x, const unsigned short& y,
const Pixel& fill_color, const Pixel& border_color);
////////////////////////////////////////////////////////////////////////////////
void MyDda(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
double x = x1;
double y = y1;
double M;
double dy = 0;
double dx = 0;
if(x2 == x1)
{
for(y = min(y1, y2); y <= max(y1,y2); y++)
{
view(unsigned short(x1), unsigned short(y)) = Pixel(0,0,255);
}
return;
}
if(y2 == y1)
{
for(y = min(x1, x2); x <= max(x1,x2); x++)
{
view(unsigned short(x), unsigned short(y1)) = Pixel(0,0,255);
}
return;
}
double delta_x = (x2-x1)/abs(x2-x1);
double delta_y = (y2-y1)/abs(y2-y1);
M = (y1 - y2) / (double)(x1 - x2);
if(abs(M) > 1)
{
M *= delta_y;
while(y != y2)
{
x = x1 + dx;
double f = x - static_cast<unsigned int>(x);
if(f > 0.75)
{
view(unsigned short(x), unsigned short(y)) = Pixel(0,0,255);
}
else if(f < 0.25)
{
view(unsigned short(x-1), unsigned short(y)) = Pixel(0,0,255);
}
else
{
int up_color = static_cast<unsigned int>(f * 255);
int down_color = 255 - up_color;
view(unsigned short(x), unsigned short(y)) = Pixel(up_color,up_color,255);
view(unsigned short(x-1), unsigned short(y)) = Pixel(down_color,down_color,255);
}
y+=delta_y;
dx+=1/M;
}
}
else
{
M *= delta_x;
while(x != x2)
{
y = y1 + dy;
double f = y - static_cast<unsigned int>(y);
if(f > 0.75)
{
view(unsigned short(x), unsigned short(y)) = Pixel(0,0,255);
}
else if(f < 0.25)
{
view(unsigned short(x), unsigned short(y-1)) = Pixel(0,0,255);
}
else
{
int down_color = static_cast<unsigned int>(f * 255);
int up_color = 255 - down_color;
view(unsigned short(x), unsigned short(y-1)) = Pixel(up_color,up_color,255);
view(unsigned short(x), unsigned short(y)) = Pixel(down_color,down_color,255);
}
x+=delta_x;
dy+=M;
}
}
}
/// DrawThisLine, function used in WndProc()
void DrawThisLine(View& view,
const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
// NOTE: Pixel(0, 0, 255) is red it's a BGR channel
//AntiAliasingDda(view, x1, y1, x2, y2);
//SymmetricDda(view, x1, y1, x2, y2);
//Bresenhama(view, x1, y1, x2, y2);
MyDda(view, x1, y1, x2, y2);
}
/// DrawThisCircle, function used in WndProc()
void DrawThisCircle(View& view,
const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
//Circle1Div4(view, x1, y1, x2, y2);
//MidpointCircle1(view, x1, y1, x2, y2);
MidpointCircle2(view, x1, y1, x2, y2);
// fail
//Ellipsis(view, x1, y1, 50, 35);
};
/// FloodThisArea, function used in WndProc()
void FloodThisArea(View& view, const unsigned short& x, const unsigned short& y)
{
// NOTE: both works for small areas, due to perhaps filling the heap memory with recurrence calls
//BoundryFill1Div4(view, x, y, Pixel(255, 0, 0), Pixel(0, 0, 255)); // works fine for small circles
BoundryFill1Div8(view, x, y, Pixel(255, 0, 0), Pixel(0, 0, 255)); // for know reasons ka-boom when circle
};
////////////////////////////////////////////////////////////////////////////////
//
void AntiAliasingDda(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
// coordinates variables
int x = x1;
float y = y1;
// y = a*x + b, linear function
const float a = float(y2 - y1) / float(x2 - x1);
const float lower_no_anti_aliasing_tolerance = 0.25f;
const float higher_no_anti_aliasing_tolerance = 0.75f;
float anti_aliasing_delta_y = 0.0f;
unsigned char down_color = 0, up_color = 0;
for (x, y; x < x2; ++x, y += a)
{
anti_aliasing_delta_y = y - static_cast<unsigned int>(y);
if (anti_aliasing_delta_y < lower_no_anti_aliasing_tolerance)
{
view(x, unsigned short(y)) = Pixel(0, 0, 255); // simplifying down
}
else if (anti_aliasing_delta_y > higher_no_anti_aliasing_tolerance)
{
view(x, unsigned short(y)+1) = Pixel(0, 0, 255); // simplifying up
}
else
{
down_color = static_cast<unsigned char>(anti_aliasing_delta_y * 255);
up_color = 255 - down_color;
view(x, unsigned short(y)) = Pixel(down_color, down_color, 255);
view(x, unsigned short(y)+1) = Pixel(up_color, up_color, 255);
}
};
}
//
void SymmetricDda(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
short delta_x = x2 - x1;
short delta_y = y2 - y1;
bool positive_delta_x = delta_x >= 0;
bool positive_delta_y = delta_y >= 0;
// maximum of two absolute values
short max_of_deltas = std::abs(delta_x) > std::abs(delta_y) ? std::abs(delta_x) : std::abs(delta_y) ;
// log2(max_of_deltas)
short n = short(std::logf((float)max_of_deltas) / std::logf(2.0f));
short pow_2_n = static_cast<short>(std::pow(2.0f, n));
// the 2^(n-1) case
if (pow_2_n < max_of_deltas)
{
pow_2_n = static_cast<short>(std::pow(2.0f, (++n)));
};
float epsilon = 1.0f / pow_2_n;
float increment_x = epsilon * delta_x;
float increment_y = epsilon * delta_y;
float x = positive_delta_x ? (x1 + 0.5f) : (x1 - 0.5f);
float y = positive_delta_y ? (y1 + 0.5f) : (y1 - 0.5f);
for (;;) // for is faster then while
{
if (x >= view.width() || y >= view.height() ||
(positive_delta_x ? (x > x2) : (x < x2)) ||
(positive_delta_y ? (y > y2) : (y < y2)) )
{
break;
};
// without anti-aliasing
view(unsigned short(x), unsigned short(y)) = Pixel(0, 0, 255);
x += increment_x;
y += increment_y;
}
}
//
void Bresenhama(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
unsigned short delta_x = x2 - x1;
unsigned short delta_y = y2 - y1;
short delta = 2 * delta_y - delta_x;
short increment_e = 2 * delta_y;
short increment_ne = 2 * (delta_y - delta_x);
unsigned short x = x1, y = y1;
Iterator_XY position = view.xy_at(x, y);
*position = Pixel(0, 0, 255);
for (; x < x2 ; ++x, ++position.x())
{
if (delta <= 0)
{
delta += increment_e;
//++x; ++position.x();
}
else
{
delta += increment_ne;
//++x; ++position.x();
++position.y(); // going north, that is south in this coordinate system :)
};
*position = Pixel(0, 0, 255);
}
}
////////////////////////////////////////////////////////////////////////////////
// draw 4 pixels
void Draw4Pixels(View& view, const unsigned short& x, const unsigned short& y,
const unsigned short& dx, const unsigned short& dy)
{
unsigned short safet_variable_x, safet_variable_y;
safet_variable_x = x + dx;
if (safet_variable_x < view.width())
{
safet_variable_y = y + dy;
if (safet_variable_y < view.height())
{
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255);
}
safet_variable_y = y - dy;
if (safet_variable_y < view.height())
{
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255);
}
}
safet_variable_x = x - dx;
if (safet_variable_x < view.width())
{
safet_variable_y = y + dy;
if (safet_variable_y < view.height())
{
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255);
}
safet_variable_y = y - dy;
if (safet_variable_y < view.height())
{
view(safet_variable_x, safet_variable_y) = Pixel(0, 0, 255);
}
}
}
// draw Bresenhama circle 1/4 (old lab task)
void Circle1Div4(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
const short radius = static_cast<short>(std::sqrt(
std::pow(static_cast<float>(x2-x1), 2.0f) +
std::pow(static_cast<float>(y2-y1), 2.0f)));
unsigned short x = 0;
unsigned short y = radius;
short delta = 2 - 2*radius;
short sigma;
for (;;)
{
// draw 4 pixels
Draw4Pixels(view, x1, y1, x, y);
if ((x == radius) && (y == 0))
{
break;
};
//sigma = delta + delta;
sigma = 2 * delta;
if (sigma < 0)
{
sigma += 2*y - 1;
if (sigma > 0) // choice D
{
++x;
--y;
delta += 2*(x - y + 1);
}
else // choice H
{
++x;
delta += 2*x + 1;
}
}
else
{
sigma += -2*x + 1;
if (sigma <= 0) // choise D
{
++x;
--y;
delta += 2*(x - y + 1);
}
else // choise V
{
--y;
delta += -2*y +1;
}
}
}
}
//
void MidpointCircle1(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
const short radius = static_cast<short>(std::sqrt(
std::pow(static_cast<float>(x2-x1), 2.0f) +
std::pow(static_cast<float>(y2-y1), 2.0f)));
unsigned short x = 0;
unsigned short y = radius;
short delta = 5 - 4*radius;
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
for (;;)
{
if (x > y)
{
break;
}
if (delta < 0)
{
delta += 4*(2*x + 3);
}
else
{
delta += 4*(2*(x - y) + 5);
--y;
}
++x;
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
}
}
//
void MidpointCircle2(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& x2, const unsigned short& y2)
{
const short radius = static_cast<short>(std::sqrt(
std::pow(static_cast<float>(x2-x1), 2.0f) +
std::pow(static_cast<float>(y2-y1), 2.0f)));
unsigned short x = 0;
unsigned short y = radius;
short delta = 5 - radius * 4;
short delta_e = 3 * 4;
short delta_se = 4*(5 - 2*radius);
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
for (;;)
{
if (x >= y)
{
break;
}
if (delta < 0)
{
delta += delta_e;
delta_e += 2 * 4;
delta_se += 2 * 4;
}
else
{
delta += delta_se;
delta_e += 2 * 4;
delta_se += 4 * 4;
--y;
}
++x;
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
}
}
////////////////////////////////////////////////////////////////////////////////
// TODO correct the code
void Ellipsis(View& view, const unsigned short& x1, const unsigned short& y1,
const unsigned short& a, const unsigned short& b)
{
unsigned short x = 0;
unsigned short y = b;
unsigned short aa = a * a;
unsigned short bb = b * b;
short delta = 4*bb - 4*b*aa + aa;
short condition = (aa * aa) / (aa + bb);
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
for (;;)
{
if (x*x > condition)
{
break;
}
if (delta < 0)
{
delta += 4*(2*x*bb + 3*bb);
}
else
{
delta += 4*(2*bb*(x - y) + 3*bb + 2*aa);
//delta += 4*(2*bb*x - 2*aa*y + 3*bb + 2*aa);
--y;
}
++x;
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
}
x = 0;
y = a;
aa = b * b;
bb = a * a;
condition = (bb * bb) / (bb + aa);
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
for (;;)
{
if (x*x > condition)
{
break;
}
if (delta < 0)
{
delta += 4*(2*x*bb + 3*bb);
}
else
{
delta += 4*(2*bb*(x - y) + 3*bb + 2*aa);
//delta += 4*(2*bb*x - 2*aa*y + 3*bb + 2*aa);
--y;
}
++x;
Draw4Pixels(view, x1, y1, x, y); // horizontal
Draw4Pixels(view, x1, y1, y, x); // vertical
}
}
////////////////////////////////////////////////////////////////////////////////
// works for small areas, due to perhaps filling the heap memory with recurrence calls
void BoundryFill1Div4(View& view, const unsigned short& x, const unsigned short& y,
const Pixel& fill_color, const Pixel& border_color)
{
Pixel color = view(x, y);
if ((color != fill_color) && (color != border_color))
{
view(x, y) = fill_color;
BoundryFill1Div4(view, x+1, y, fill_color, border_color);
BoundryFill1Div4(view, x-1, y, fill_color, border_color);
BoundryFill1Div4(view, x, y+1, fill_color, border_color);
BoundryFill1Div4(view, x, y-1, fill_color, border_color);
}
}
// works for small quadratic-like areas, due to perhaps filling the heap memory with recurrence calls
void BoundryFill1Div8(View& view, const unsigned short& x, const unsigned short& y,
const Pixel& fill_color, const Pixel& border_color)
{
// NOTE: the eight neighbourhood implementation is useless when dealing with e.g. circles
Pixel color = view(x, y);
if ((color != fill_color) && (color != border_color))
{
view(x, y) = fill_color;
BoundryFill1Div8(view, x+1, y, fill_color, border_color);
BoundryFill1Div8(view, x-1, y, fill_color, border_color);
BoundryFill1Div8(view, x, y+1, fill_color, border_color);
BoundryFill1Div8(view, x, y-1, fill_color, border_color);
BoundryFill1Div8(view, x+1, y+1, fill_color, border_color);
BoundryFill1Div8(view, x+1, y-1, fill_color, border_color);
BoundryFill1Div8(view, x-1, y+1, fill_color, border_color);
BoundryFill1Div8(view, x-1, y-1, fill_color, border_color);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment