Java: Converting RGB to ARGB to be used in BufferImage setRGB - rgb

I'm trying to make a dithering effect to just mess around with in my free time to hopefully learn more about java interfacing. i found out how to convert the 32 bit ARGB int which you get when using the .getRGB(x,y) for a BufferedImage and did the calculations to change the color to the red green and blue values that i would need. Now all I have to do is turn these red green and blue float values into an ARGB int again to be used in the setRGB(x,y,rgb) method. Thanks!
private static void dither(BufferedImage bi) {
int width = bi.getWidth();
int height = bi.getHeight();
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++) {
int rgb = bi.getRGB(x, y);
float red = (rgb >> 16) & 0x000000FF;
float green = (rgb >>8 ) & 0x000000FF;
float blue = (rgb) & 0x000000FF;
red = Math.round(red / 255) * 255;
green = Math.round(green / 255) * 255;
blue = Math.round(blue / 255) * 255;
bi.setRGB(x, y, rgb); //this is where i need the red, green, blue values to be a single int
}
}
}
I'm thinking maybe I'd have to do the opposite of what i did to get the individual red, green and blue values but I'm not sure.
Please note I am still VERY new to coding and so please feel free to give me feedback on naming conventions and syntax.

Related

My Sepia filter is not working as expected, although in certain cases it does work

For my online CS50 course I have to convert an image to Sepia.
I have built this function that should take each pixel and sets the RGB value to Sepia.
The program loads an image via the command prompt and converts its to Sepia.
The programs loads the picture fine, and it also creates a new picture.
Only problem is it is not Sepia. Online I can check my program, here it sometimes calculates the new pixel correct but other times it is wrong. I cannot see any connections on why it works only with some pixels. Probably has to do with the values of the pixel, but I cannot see the input. The formula for sepia was given by Harvard CS50.
Here is a link to the results: https://submit.cs50.io/check50/66b21d4d9453a5e671bb0862bb016a420a73893b
Here is the code that should change the image to Sepia.
// Convert image to sepia
void sepia(int height, int width, RGBTRIPLE image[height][width])
{
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
//Calculates the sepia value of image[i][j].rgbtRed
int red = round((image[i][j].rgbtRed *.393)+(image[i][j].rgbtGreen *.769)+(image[i][j].rgbtBlue *.189));
//the value can be max 255, if it is higher it should be capped at 255
if (red > 255)
{
red = 255;
}
//Calculates the sepia value of image[i][j].rgbtGreen
int green = round((image[i][j].rgbtRed *.349)+(image[i][j].rgbtGreen *.686)+(image[i][j].rgbtBlue *.168));
if (green > 255)
{
green = 255;
}
//Calculates the sepia value of image[i][j].rgbtblue
int blue = round((image[i][j].rgbtRed *.272)+(image[i][j].rgbtGreen *.534)+(image[i][j].rgbtBlue *.131));
if (blue > 255)
{
blue = 255;
}
//sets the image[i][j] values to the Sepia equavalent
image[i][j].rgbtRed = red;
image[i][j].rgbtGreen = green;
image[i][j].rgbtBlue = blue;
}
return;
}
}

Skin Color Detection in OpenCV

I trying to do skin color detection in Opencv.
1) First i converted the image into HSV from RGB
cvCvtColor(frame, hsv, CV_BGR2HSV);
2) Than i had applied skin color threshold in the HSV image
cvInRangeS(hsv, hsv_min, hsv_max, mask); // hsv_min & hsv_max are the value for skin detection
3) So it generates the mash which has only skin color but in Black & white image, so i converted that image in to RGB
cvCvtColor(mask, temp, CV_GRAY2RGB);
4) so now i want the skin color in only RGB value.
for(c = 0; c < frame -> height; c++) {
uchar* ptr = (uchar*) ((frame->imageData) + (c * frame->widthStep));
uchar* ptr2 = (uchar*) ((temp->imageData) + (c * temp->widthStep));
for(d = 0; d < frame -> width; d++) {
if(ptr2[3*d+0] != 255 && ptr2[3*d+1] != 255 && ptr2[3*d+2] != 255 && ptr2[3*d+3] != 255 ){
ptr[3 * d + 0] = 0;
ptr[3 * d + 1] = 0;
ptr[3 * d + 2] = 0;
ptr[3 * d + 3] = 0;
}
}
}
now i am not getting the image that i want actually that has only skin color in RGB.
Any Solution,
Thanks
1st Original Image
2nd Skin Detected Image in Black & White
3rd Output (Not Actual)
you're already quite close.
given, you have a 3 channel mask already:
Mat mask, temp;
cv::cvtColor(mask, temp, CV_GRAY2RGB);
all you need to do is combine it with your original image to mask out all non-skin color:
(and no, don't write [error prone] loops there, better rely on the builtin functionality !)
Mat draw = frame & temp; // short for bitwise_and()
imshow("skin",draw);
waitKey();
Alternatively, without having to convert mask to RGB, you could .copyTo() passing the mask parameter
cv::cvtColor(inputFrame, hsv, CV_BGR2HSV);
cv::inRange(hsv, hsv_min, hsv_max, mask);
cv::Mat outputFrame;
inputFrame.copyTo(outputFrame, mask);

WPF WriteableBitmap problems with transparency

First of all Ill explain what I try to do, just in the case that someone comes up with a better approach
I need to blend too images using the "color" stile from photoshop (you know, the blending methods: Screen, hard light, color ... )
So, I have my base image (a png) and WriteableBitmap generated on execution time (lets call it color mask). Then I need to blend this two images using the "color" method and show the result in a UI component.
So far what Im trying is just to draw things on the WriteableBitmap but I'm facing unexpected behavior with the alpha channel.
My code so far:
// variables declaration
WriteableBitmap img = new WriteableBitmap(width, height, 96,96,PixelFormats.Bgra32,null);
pixels = new uint[width * height];
//function for setting the color of one pixel
private void SetPixel(int x, int y, Color c)
{
int pixel = width * y + x;
int red = c.R;
int green = c.G;
int blue = c.B;
int alpha = c.A;
pixels[pixel] = (uint)((blue << 24) + (green << 16) + (red << 8) + alpha);
}
//function for paint all the pixels of the image
private void Render()
{
Color c = new Color();
c.R = 255; c.G = 255; c.B = 255; c.A = 50;
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
SetPixel(x, y, c);
img.WritePixels(new Int32Rect(0, 0, width, height), pixels, width * 4, 0);
image1.Source = img; // image1 is a WPF Image in my XAML
}
Whenever I run the code with the color c.A = 255 I get the expected results. The whole Image is set to the desired color. But if I set c.A to a different value I get weird things.
If I set the color to BRGA = 0,0,255,50 I get a dark blue almost black. If I set it to BRGA = 255,255,255,50 I get a yellow ...
Any clue !?!?!
Thanks in advance !
Change the order of your colour components to
pixels[pixel] = (uint)((alpha << 24) + (red << 16) + (green << 8) + blue);

MagickWand for C, error when calling DestroyPixelWands

I am starting to use ImageMagick and the MagickWand API in a simple C program.
Right now, as a test, I am just looking for black pixels in a frame.
Here is my code :
int find_black_pixel(MagickWand *wand) {
int res = 0;
PixelIterator * iterator = NewPixelIterator(wand);
size_t width=MagickGetImageWidth(wand);
size_t height=MagickGetImageHeight(wand);
PixelWand ** pixels;
unsigned long x,y;
unsigned int alpha;
unsigned int red, green, blue;
//printf("Width : %d, Height : %d\n", (int)width, (int)height);
for (y=0; y<height; y++) {
pixels = PixelGetNextIteratorRow(iterator, &width);
for (x=0; x<width; x++) {
alpha = (unsigned int) (255*PixelGetAlpha(pixels[x]));
if (alpha == 0)
continue;
red = (unsigned int) (255*PixelGetRed(pixels[x]));
green = (unsigned int) (255*PixelGetGreen(pixels[x]));
blue = (unsigned int) (255*PixelGetBlue(pixels[x]));
//printf("At %04ld,%04ld, alpha : %d, rgb : %d,%d,%d\n", x,y,alpha, red, green, blue);
if ((red ==0) || (green == 0) || (blue ==0)) {
res = 1;
//DestroyPixelWands(pixels, width);
goto finished_find_black_pixel;
}
}
//DestroyPixelWands(pixels, (size_t)width);
}
finished_find_black_pixel:
DestroyPixelIterator(iterator);
return res;
}
If I uncomment any of the DestroyPixelWands call, I get an assertion :
test: wand/pixel-wand.c:283: DestroyPixelWands: Assertion `(*wand)->signature == 0xabacadabUL' failed.
Any idea why this is happening ?
EDIT :
More debugging... Even calling DestroyPixelWand(pixels[0]); makes it fail the same way...
I suspect that pixels is not a separate destroyable object (it is just a pointer into the original wand object) and that your current code is fine without any code to destroy pixels.
Got the answer from ImageMagick forum :
The pixel wands are private when associated with a pixel iterator. The
pixel wands are destroyed when you destroy the pixel iterator. Do not
use DestroyPixelWands() for a pixel iterator.

fast algorithm for drawing filled circles?

I am using Bresenham's circle algorithm for fast circle drawing. However, I also want to (at the request of the user) draw a filled circle.
Is there a fast and efficient way of doing this? Something along the same lines of Bresenham?
The language I am using is C.
Having read the Wikipedia page on Bresenham's (also 'Midpoint') circle algorithm, it would appear that the easiest thing to do would be to modify its actions, such that instead of
setPixel(x0 + x, y0 + y);
setPixel(x0 - x, y0 + y);
and similar, each time you instead do
lineFrom(x0 - x, y0 + y, x0 + x, y0 + y);
That is, for each pair of points (with the same y) that Bresenham would you have you plot, you instead connect with a line.
Just use brute force. This method iterates over a few too many pixels, but it only uses integer multiplications and additions. You completely avoid the complexity of Bresenham and the possible bottleneck of sqrt.
for(int y=-radius; y<=radius; y++)
for(int x=-radius; x<=radius; x++)
if(x*x+y*y <= radius*radius)
setpixel(origin.x+x, origin.y+y);
Here's a C# rough guide (shouldn't be that hard to get the right idea for C) - this is the "raw" form without using Bresenham to eliminate repeated square-roots.
Bitmap bmp = new Bitmap(200, 200);
int r = 50; // radius
int ox = 100, oy = 100; // origin
for (int x = -r; x < r ; x++)
{
int height = (int)Math.Sqrt(r * r - x * x);
for (int y = -height; y < height; y++)
bmp.SetPixel(x + ox, y + oy, Color.Red);
}
bmp.Save(#"c:\users\dearwicker\Desktop\circle.bmp");
You can use this:
void DrawFilledCircle(int x0, int y0, int radius)
{
int x = radius;
int y = 0;
int xChange = 1 - (radius << 1);
int yChange = 0;
int radiusError = 0;
while (x >= y)
{
for (int i = x0 - x; i <= x0 + x; i++)
{
SetPixel(i, y0 + y);
SetPixel(i, y0 - y);
}
for (int i = x0 - y; i <= x0 + y; i++)
{
SetPixel(i, y0 + x);
SetPixel(i, y0 - x);
}
y++;
radiusError += yChange;
yChange += 2;
if (((radiusError << 1) + xChange) > 0)
{
x--;
radiusError += xChange;
xChange += 2;
}
}
}
Great ideas here!
Since I'm at a project that requires many thousands of circles to be drawn, I have evaluated all suggestions here (and improved a few by precomputing the square of the radius):
http://quick-bench.com/mwTOodNOI81k1ddaTCGH_Cmn_Ag
The Rev variants just have x and y swapped because consecutive access along the y axis are faster with the way my grid/canvas structure works.
The clear winner is Daniel Earwicker's method ( DrawCircleBruteforcePrecalc ) that precomputes the Y value to avoid unnecessary radius checks. Somewhat surprisingly that negates the additional computation caused by the sqrt call.
Some comments suggest that kmillen's variant (DrawCircleSingleLoop) that works with a single loop should be very fast, but it's the slowest here. I assume that is because of all the divisions. But perhaps I have adapted it wrong to the global variables in that code. Would be great if someone takes a look.
EDIT: After looking for the first time since college years at some assembler code, I managed find that the final additions of the circle's origin are a culprit.
Precomputing those, I improved the fastest method by a factor of another 3.7-3.9 according to the bench!
http://quick-bench.com/7ZYitwJIUgF_OkDUgnyMJY4lGlA
Amazing.
This being my code:
for (int x = -radius; x < radius ; x++)
{
int hh = (int)std::sqrt(radius_sqr - x * x);
int rx = center_x + x;
int ph = center_y + hh;
for (int y = center_y-hh; y < ph; y++)
canvas[rx][y] = 1;
}
I like palm3D's answer. For being brute force, this is an amazingly fast solution. There are no square root or trigonometric functions to slow it down. Its one weakness is the nested loop.
Converting this to a single loop makes this function almost twice as fast.
int r2 = r * r;
int area = r2 << 2;
int rr = r << 1;
for (int i = 0; i < area; i++)
{
int tx = (i % rr) - r;
int ty = (i / rr) - r;
if (tx * tx + ty * ty <= r2)
SetPixel(x + tx, y + ty, c);
}
This single loop solution rivals the efficiency of a line drawing solution.
int r2 = r * r;
for (int cy = -r; cy <= r; cy++)
{
int cx = (int)(Math.Sqrt(r2 - cy * cy) + 0.5);
int cyy = cy + y;
lineDDA(x - cx, cyy, x + cx, cyy, c);
}
palm3D's brute-force algorithm I found to be a good starting point. This method uses the same premise, however it includes a couple of ways to skip checking most of the pixels.
First, here's the code:
int largestX = circle.radius;
for (int y = 0; y <= radius; ++y) {
for (int x = largestX; x >= 0; --x) {
if ((x * x) + (y * y) <= (circle.radius * circle.radius)) {
drawLine(circle.center.x - x, circle.center.x + x, circle.center.y + y);
drawLine(circle.center.x - x, circle.center.x + x, circle.center.y - y);
largestX = x;
break; // go to next y coordinate
}
}
}
Next, the explanation.
The first thing to note is that if you find the minimum x coordinate that is within the circle for a given horizontal line, you immediately know the maximum x coordinate.
This is due to the symmetry of the circle. If the minimum x coordinate is 10 pixels ahead of the left of the bounding box of the circle, then the maximum x is 10 pixels behind the right of the bounding box of the circle.
The reason to iterate from high x values to low x values, is that the minimum x value will be found with less iterations. This is because the minimum x value is closer to the left of the bounding box than the centre x coordinate of the circle for most lines, due to the circle being curved outwards, as seen on this image
The next thing to note is that since the circle is also symmetric vertically, each line you find gives you a free second line to draw, each time you find a line in the top half of the circle, you get one on the bottom half at the radius-y y coordinate. Therefore, when any line is found, two can be drawn and only the top half of the y values needs to be iterated over.
The last thing to note is that is that if you start from a y value that is at the centre of the circle and then move towards the top for y, then the minimum x value for each next line must be closer to the centre x coordinate of the circle than the last line. This is also due to the circle curving closer towards the centre x value as you go up the circle. Here is a visual on how that is the case.
In summary:
If you find the minimum x coordinate of a line, you get the maximum x coordinate for free.
Every line you find to draw on the top half of the circle gives you a line on the bottom half of the circle for free.
Every minimum x coordinate has to be closer to the centre of the circle than the previous x coordinate for each line when iterating from the centre y coordinate to the top.
You can also store the value of (radius * radius), and also (y * y) instead of calculating them
multiple times.
Here's how I'm doing it:
I'm using fixed point values with two bits precision (we have to manage half points and square values of half points)
As mentionned in a previous answer, I'm also using square values instead of square roots.
First, I'm detecting border limit of my circle in a 1/8th portion of the circle. I'm using symetric of these points to draw the 4 "borders" of the circle. Then I'm drawing the square inside the circle.
Unlike the midpoint circle algorith, this one will work with even diameters (and with real numbers diameters too, with some little changes).
Please forgive me if my explanations were not clear, I'm french ;)
void DrawFilledCircle(int circleDiameter, int circlePosX, int circlePosY)
{
const int FULL = (1 << 2);
const int HALF = (FULL >> 1);
int size = (circleDiameter << 2);// fixed point value for size
int ray = (size >> 1);
int dY2;
int ray2 = ray * ray;
int posmin,posmax;
int Y,X;
int x = ((circleDiameter&1)==1) ? ray : ray - HALF;
int y = HALF;
circlePosX -= (circleDiameter>>1);
circlePosY -= (circleDiameter>>1);
for (;; y+=FULL)
{
dY2 = (ray - y) * (ray - y);
for (;; x-=FULL)
{
if (dY2 + (ray - x) * (ray - x) <= ray2) continue;
if (x < y)
{
Y = (y >> 2);
posmin = Y;
posmax = circleDiameter - Y;
// Draw inside square and leave
while (Y < posmax)
{
for (X = posmin; X < posmax; X++)
setPixel(circlePosX+X, circlePosY+Y);
Y++;
}
// Just for a better understanding, the while loop does the same thing as:
// DrawSquare(circlePosX+Y, circlePosY+Y, circleDiameter - 2*Y);
return;
}
// Draw the 4 borders
X = (x >> 2) + 1;
Y = y >> 2;
posmax = circleDiameter - X;
int mirrorY = circleDiameter - Y - 1;
while (X < posmax)
{
setPixel(circlePosX+X, circlePosY+Y);
setPixel(circlePosX+X, circlePosY+mirrorY);
setPixel(circlePosX+Y, circlePosY+X);
setPixel(circlePosX+mirrorY, circlePosY+X);
X++;
}
// Just for a better understanding, the while loop does the same thing as:
// int lineSize = circleDiameter - X*2;
// Upper border:
// DrawHorizontalLine(circlePosX+X, circlePosY+Y, lineSize);
// Lower border:
// DrawHorizontalLine(circlePosX+X, circlePosY+mirrorY, lineSize);
// Left border:
// DrawVerticalLine(circlePosX+Y, circlePosY+X, lineSize);
// Right border:
// DrawVerticalLine(circlePosX+mirrorY, circlePosY+X, lineSize);
break;
}
}
}
void DrawSquare(int x, int y, int size)
{
for( int i=0 ; i<size ; i++ )
DrawHorizontalLine(x, y+i, size);
}
void DrawHorizontalLine(int x, int y, int width)
{
for(int i=0 ; i<width ; i++ )
SetPixel(x+i, y);
}
void DrawVerticalLine(int x, int y, int height)
{
for(int i=0 ; i<height ; i++ )
SetPixel(x, y+i);
}
To use non-integer diameter, you can increase precision of fixed point or use double values.
It should even be possible to make a sort of anti-alias depending on the difference between dY2 + (ray - x) * (ray - x) and ray2 (dx² + dy² and r²)
If you want a fast algorithm, consider drawing a polygon with N sides, the higher is N, the more precise will be the circle.
I would just generate a list of points and then use a polygon draw function for the rendering.
It may not be the algorithm yo are looking for and not the most performant one,
but I always do something like this:
void fillCircle(int x, int y, int radius){
// fill a circle
for(int rad = radius; rad >= 0; rad--){
// stroke a circle
for(double i = 0; i <= PI * 2; i+=0.01){
int pX = x + rad * cos(i);
int pY = y + rad * sin(i);
drawPoint(pX, pY);
}
}
}
The following two methods avoid the repeated square root calculation by drawing multiple parts of the circle at once and should therefore be quite fast:
void circleFill(const size_t centerX, const size_t centerY, const size_t radius, color fill) {
if (centerX < radius || centerY < radius || centerX + radius > width || centerY + radius > height)
return;
const size_t signedRadius = radius * radius;
for (size_t y = 0; y < radius; y++) {
const size_t up = (centerY - y) * width;
const size_t down = (centerY + y) * width;
const size_t halfWidth = roundf(sqrtf(signedRadius - y * y));
for (size_t x = 0; x < halfWidth; x++) {
const size_t left = centerX - x;
const size_t right = centerX + x;
pixels[left + up] = fill;
pixels[right + up] = fill;
pixels[left + down] = fill;
pixels[right + down] = fill;
}
}
}
void circleContour(const size_t centerX, const size_t centerY, const size_t radius, color stroke) {
if (centerX < radius || centerY < radius || centerX + radius > width || centerY + radius > height)
return;
const size_t signedRadius = radius * radius;
const size_t maxSlopePoint = ceilf(radius * 0.707106781f); //ceilf(radius * cosf(TWO_PI/8));
for (size_t i = 0; i < maxSlopePoint; i++) {
const size_t depth = roundf(sqrtf(signedRadius - i * i));
size_t left = centerX - depth;
size_t right = centerX + depth;
size_t up = (centerY - i) * width;
size_t down = (centerY + i) * width;
pixels[left + up] = stroke;
pixels[right + up] = stroke;
pixels[left + down] = stroke;
pixels[right + down] = stroke;
left = centerX - i;
right = centerX + i;
up = (centerY - depth) * width;
down = (centerY + depth) * width;
pixels[left + up] = stroke;
pixels[right + up] = stroke;
pixels[left + down] = stroke;
pixels[right + down] = stroke;
}
}
This was used in my new 3D printer Firmware, and it is proven the
fastest way for filled circle of a diameter from 1 to 43 pixel. If
larger is needed, the following memory block(or array) should be
extended following a structure I wont waste my time explaining...
If you have questions, or need larger diameter than 43, contact me, I
will help you drawing the fastest and perfect filled circles... or
Bresenham's circle drawing algorithm can be used above those
diameters, but having to fill the circle after, or incorporating the
fill into Bresenham's circle drawing algorithm, will only result in
slower fill circle than my code. I already benchmarked the different
codes, my solution is 4 to 5 times faster. As a test I have been
able to draw hundreds of filled circles of different size and colors
on a BigTreeTech tft24 1.1 running on a 1-core 72 Mhz cortex-m4
https://www.youtube.com/watch?v=7_Wp5yn3ADI
// this must be declared anywhere, as static or global
// as long as the function can access it !
uint8_t Rset[252]={
0,1,1,2,2,1,2,3,3,1,3,3,4,4,2,3,4,5,5,5,2,4,5,5,
6,6,6,2,4,5,6,6,7,7,7,2,4,5,6,7,7,8,8,8,2,5,6,7,
8,8,8,9,9,9,3,5,6,7,8,9,9,10,10,10,10,3,5,7,8,9,
9,10,10,11,11,11,11,3,5,7,8,9,10,10,11,11,12,12,
12,12,3,6,7,9,10,10,11,12,12,12,13,13,13,13,3,6,
8,9,10,11,12,12,13,13,13,14,14,14,14,3,6,8,9,10,
11,12,13,13,14,14,14,15,15,15,15,3,6,8,10,11,12,
13,13,14,14,15,15,15,16,16,16,16,4,7,8,10,11,12,
13,14,14,15,16,16,16,17,17,17,17,17,4,7,9,10,12,
13,14,14,15,16,16,17,17,17,18,18,18,18,18,4,7,9,
11,12,13,14,15,16,16,17,17,18,18,18,19,19,19,19,
19,7,9,11,12,13,15,15,16,17,18,18,19,19,20,20,20,
20,20,20,20,20,7,9,11,12,14,15,16,17,17,18,19,19
20,20,21,21,21,21,21,21,21,21};
// SOLUTION 1: (the fastest)
void FillCircle_v1(uint16_t x, uint16_t y, uint16_t r)
{
// all needed variables are created and set to their value...
uint16_t radius=(r<1) ? 1 : r ;
if (radius>21 ) {radius=21; }
uint16_t diam=(radius*2)+1;
uint16_t ymir=0, cur_y=0;
radius--; uint16_t target=(radius*radius+3*radius)/2; radius++;
// this part draws directly into the ILI94xx TFT buffer mem.
// using pointers..2 versions where you can draw
// pixels and lines with coordinates will follow
for (uint16_t yy=0; yy<diam; yy++)
{ ymir= (yy<=radius) ? yy+target : target+diam-(yy+1);
cur_y=y-radius+yy;
uint16_t *pixel=buffer_start_addr+x-Rset[ymir]+cur_y*buffer_width;
for (uint16_t xx= 0; xx<=(2*Rset[ymir]); xx++)
{ *pixel++ = CANVAS::draw_color; }}}
// SOLUTION 2: adaptable to any system that can
// add a pixel at a time: (drawpixel or add_pixel,etc_)
void FillCircle_v2(uint16_t x, uint16_t y, uint16_t r)
{
// all needed variables are created and set to their value...
uint16_t radius=(r<1) ? 1 : r ;
if (radius>21 ) {radius=21; }
uint16_t diam=(radius*2)+1;
uint16_t ymir=0, cur_y=0;
radius--; uint16_t target=(radius*radius+3*radius)/2; radius++;
for (uint16_t yy=0; yy<diam; yy++)
{ ymir= (yy<=radius) ? yy+target : target+diam-(yy+1);
cur_y=y-radius+yy;
uint16_t Pixel_x=x-Rset[ymir];
for (uint16_t xx= 0; xx<=(2*Rset[ymir]); xx++)
{ //use your add_pixel or draw_pixel here
// using those coordinates:
// X position will be... (Pixel_x+xx)
// Y position will be... (cur_y)
// and add those 3 brackets at the end
}}}
// SOLUTION 3: adaptable to any system that can draw fast
// horizontal lines
void FillCircle_v3(uint16_t x, uint16_t y, uint16_t r)
{
// all needed variables are created and set to their value...
uint16_t radius=(r<1) ? 1 : r ;
if (radius>21 ) {radius=21; }
uint16_t diam=(radius*2)+1;
uint16_t ymir=0, cur_y=0;
radius--; uint16_t target=(radius*radius+3*radius)/2; radius++;
for (uint16_t yy=0; yy<diam; yy++)
{ ymir= (yy<=radius) ? yy+target : target+diam-(yy+1);
cur_y=y-radius+yy;
uint16_t start_x=x-Rset[ymir];
uint16_t width_x=2*Rset[ymir];
// ... then use your best drawline function using those values:
// start_x: position X of the start of the line
// cur_y: position Y of the current line
// width_x: length of the line
// if you need a 2nd coordinate then :end_x=start_x+width_x
// and add those 2 brackets after !!!
}}
I did pretty much what AlegGeorge did but I changed three lines. I thought that this is faster but these are the results am I doing anything wrong? my function is called DrawBruteforcePrecalcV4. here's the code:
for (int x = 0; x < radius ; x++) // Instead of looping from -radius to radius I loop from 0 to radius
{
int hh = (int)std::sqrt(radius_sqr - x * x);
int rx = center_x + x;
int cmx = center_x - x;
int ph = center_y+hh;
for (int y = center_y-hh; y < ph; y++)
{
canvas[rx][y] = 1;
canvas[cmx][y] = 1;
}
}

Resources