

Density-Based Resampling for Digital Images and an Example: Fake Antique Mozaics
source link: https://www.codeproject.com/Articles/5329337/Density-Based-Resampling-for-Digital-Images-and-an
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Introduction
In this article, I'll present a new and a very simple method to resampling points from a digital image and drawing it looking like as antique mosaics, dots (stippling) and Voronoi cells. This method is based on calculating density-based kernel size, then taking a sample and eliminating the remaining neighbour points spanned by circular kernel.
Before you go on, I strongly recommend that you check the articles in the References section.
The common way to explain a method and its logical background is starting to show what we want to do:
The first step is to get resampling points and the second one is to draw what we want using these sampled points.
Input Image Sampled points
Fake Antique Mosaics Dots (Stippling)
Voronoi Cells Dots (stroke)
The Method
Technically, resampling a digital image is known as "spatial sampling". There are many sampling methods used in practice, such as regular grid, irregular grid, hexagonal grid, triangular grid, Poission disk sampling, random sampling, quassi-random sampling, etc. Some of these sampling methods have deep relations with statistical distributions. The main aim is to get a balanced distribution (i.e., sampling points) as statistically in math and as aesthetically in artistic stylisation. Here, I'll explain yet another sampling method based on density. For digital images, we accepts that "density" is the image's luminance (i.e., pixels' gray levels).
Steps
This is input image and its pixels.
Let's scan all pixels in the image over the following steps. 1. Convert image to grayscale.
2. Get gray values of each pixel.
3. Calculate circular kernel radius based on that gray values (i.e., density.)
4. Eliminate the remain neighbour pixels in circular kernel (window).
5. As a result, we've got a resampled pixel and the other white pixels.
If we repeat these steps for each pixels, we get all resampled pixels. So, the first step is done.
After that, we'll draw some shapes based on those sampled pixels' color and related radius values calculated before. These are easier steps and don't need explanation.
So, now, please check the top images again as a lightened mind.
The Code
The formula for calculating the kernel radius is a calculated formula that is my own all property.
kernelRadius := (256 div density) - (gray div density);
Typical parameter values are 20 for density and 192 for threshold.
Using the Code
Lead with core punchline codes!
type TCDots = record Cx, Cy: integer; CRadius: integer; CColor: TColor; end; var dots: array of TCDots; ... ... SetLength(dots, nSize); ... ... for y:=0 to H-1 do begin for x:=0 to W-1 do begin c := imgWork.Canvas.Pixels[x, y]; r := GetRValue(c); g := GetGValue(c); b := GetBValue(c); gray := trunc(r * 0.2989 + g * 0.5866 + b * 0.1145 + 0.5); ////////////////////////////////////////////////////////////// // (c) Copyright AG 2022. [email protected] // Not allowed to use for commercial apps without permissions. kernelRadius := (256 div density) - (gray div density); // copyrighted if chkFixedDensity.Checked then kernelRadius := 16 - (gray div 32); // trivial ////////////////////////////////////////////////////////////// if (kernelRadius < 5) then kernelRadius := 5; radii2 := kernelRadius * kernelRadius; if (gray > threshold) then begin c1 := clWhite; imgWork.Canvas.Pixels[x, y] := c1; continue; end; // stippling for ky:=-kernelRadius to +kernelRadius do begin yy := y + ky; if (yy < 0) then yy := 0; if (yy > H-1) then yy := H-1; for kx:=-kernelRadius to +kernelRadius do begin xx := x + kx; if (xx < 0) then xx := 0; if (xx > W-1) then xx := W-1; if ( (ky = 0) and (kx = 0) ) then c1 := c else c1 := clWhite; if (kx*kx + ky*ky < radii2) then begin imgWork.Canvas.Pixels[xx, yy] := c1; if (c1 <> clWhite) then with dots[nCount] do begin Cx := xx; Cy := yy; CRadius := kernelRadius; CColor := c1; end; end; // if end; // kx end; // ky ... end; // x ... end; // y ...
NOTE: For simplicity, here I've used Canvas.Pixels[..]
, but, to optimize for speed, please DON'T use Canvas.Pixels[..]
in real applications.
Conclusion and Points of Interest
To be honest, nothing to discuss. To avoid more complex and expensive cost methods, please follow me. :)
References
History
- 7th April, 2022: Initial version
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK