Calculates the center of gravity (COG) of a character-like binary image based on potential energy.
Usage
cog_potential(img, origin = c("bottomleft", "topleft"))
Arguments
- img
An image input, either a file path to an image file (e.g., PNG, JPEG), or a
cimg
object from the imager package. The image should be in binary form, with foreground (glyph) values not equal to 1 and background values equal to 1.- origin
A character string indicating the location of the image origin. Use
"bottomleft"
(default) if the y-axis increases upward (Cartesian), or"topleft"
if the y-axis increases downward (as in image arrays).
Value
A list containing:
statistics
A data frame with the following components:
center_x
,center_y
: The (x, y) coordinates of the COG in pixel coordinates of the input image.center_x_trim
,center_y_trim
: The COG coordinates relative to the trimmed glyph region, excluding image margins.center_x_std
,center_y_std
: The standardized COG coordinates ranging from 0 to 1, based on the trimmed region's width and height.margin_left
,margin_right
,margin_top
,margin_bottom
: Margins between the glyph and the image boundary.width_original
,height_original
: Dimensions of the original image.width_trim
,height_trim
: Width and height of the trimmed glyph region, excluding margins.
potentials
A data frame containing the (x, y) coordinates and the normalized potential value for each pixel within the convex hull. The potentials are normalized so that their sum equals 1.
Details
In the potential energy-based method, the center of gravity (COG) is defined as the weighted mean of the coordinates of all pixels within the convex hull of the stroke region, where the weight at each pixel is determined by the potential induced by all other stroke pixels. The method assumes that each stroke pixel contributes a unit mass and exerts an attractive force on all other pixels within the convex polygon, inversely proportional to their distance, modeling a simplified gravitational interaction. To avoid excessive computation, unintended influence from remote regions, and to restrict the analysis to a perceptually relevant area, the potential is computed only within the convex polygon (i.e., the same region used in the contour-based COG calculation), rather than across the entire image.
Let \(S\) be the set of all stroke pixels, and let \(R\) be the set of all pixels within the convex polygon region. The potential at each pixel \((x, y) \in R\) is defined as:
$$ p(x, y) = \sum_{\substack{(x', y') \in S \\ (x', y') \ne (x, y)}} \frac{1}{\sqrt{(x - x')^2 + (y - y')^2}} $$
That is, the potential at each point in \(R\) is the sum of the inverse distances to all stroke pixels in \(S\), excluding the case where \((x', y') = (x, y)\). Pixels outside the convex polygon are assigned a potential value of zero and do not contribute to the COG calculation.
Then, the center of gravity is computed as:
$$ G_x = \left( \sum_{(x, y) \in R} p(x, y) \cdot x \right) / \left( \sum_{(x, y) \in R} p(x, y) \right) $$ $$ G_y = \left( \sum_{(x, y) \in R} p(x, y) \cdot y \right) / \left( \sum_{(x, y) \in R} p(x, y) \right) $$
In other words, the COG corresponds to the weighted mean of pixel coordinates in the convex region, where weights are given by their potential values induced by the distribution of stroke pixels.
This method was originally proposed by Kotani et al. (2006) and has been used in character analysis and font design to reflect the perceived shape of glyphs more robustly than simple stroke averaging, and to further improve upon the contour-based COG by incorporating the spatial distribution of strokes within the convex polygon, thereby aligning more closely with the subjective impression of a character's center.
References
Kotani, A., Tanemura, Y., Mitsuyama, Y., Asai, Y., Nakamura, Y., & Onoye, T. (2006). Potential energy-based center of gravity evaluation of characters. The Journal of the Institute of Image Electronics Engineers of Japan, 35(4), 296–305. doi:10.11371/iieej.35.296
Examples
# \donttest{
data(img_A) # load example image from the package
result <- cog_potential(img_A, origin = "bottomleft")
result$statistics # summary data frame
#> center_x center_y center_x_trim center_y_trim center_x_std center_y_std
#> 1 250.4813 209.9258 189.4813 180.9258 0.4999506 0.4102626
#> margin_left margin_right margin_top margin_bottom width_original
#> 1 61 61 31 29 500
#> height_original width_trim height_trim
#> 1 500 378 440
head(result$potentials) # pixel coordinates with normalized potential values
#> x y value
#> 1 223 32 0.5956361
#> 2 224 32 0.6030280
#> 3 225 32 0.6086636
#> 4 226 32 0.6134050
#> 5 227 32 0.6175465
#> 6 228 32 0.6212331
result$origin # image origin specification
#> [1] "bottomleft"
# }