Skip to content

Commit 9e3c690

Browse files
committed
c++ style in markdown
1 parent 291e2f8 commit 9e3c690

File tree

1 file changed

+21
-32
lines changed

1 file changed

+21
-32
lines changed

_posts/2025-01-20-shape-normalization.md

Lines changed: 21 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,7 @@ Let’s have a look at some images we would like to normalize in shape. We want
5454
</table>
5555

5656
The characters can be written in either white or black. To add some adaptability, we will threshold at 127 (considering 8-bit depth), rescale the image to a size of 512x512, and calculate the relative percentage of white pixels in the image. If this percentage is less than 0.5, we are dealing with an image where white pixels dominate, and therefore the character will be made white. Finally, we will scale the amplitude to the range [0-1]:
57-
```C++
58-
// Preprocessing of the input image
59-
image.setTo(0, image < 127);
60-
cv::resize(image, image, cv::Size(512, 512), 0.0, 0.0, cv::INTER_LINEAR_EXACT);
61-
blancos_pct > 0.5 ?
62-
cv::threshold(image, image, 127, 255, cv::THRESH_BINARY_INV) :
63-
cv::threshold(image, image, 127, 255, cv::THRESH_BINARY);
64-
image.convertTo(image, CV_64FC1, 1.0 / 255.0, 0.0);
65-
66-
```
57+
{% gist 89f5c2fb2cb6159d792dc543d72d2b61 %}
6758

6859
<table>
6960
<caption>Above: input characters. Below: their binarized versions.</caption>
@@ -83,14 +74,12 @@ image.convertTo(image, CV_64FC1, 1.0 / 255.0, 0.0);
8374

8475
### Algorithm
8576
1. The first step to normalize the shape of the object is to compute its centroid (x_hat, y_hat):
86-
$
87-
\bar{x} = \frac{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} x \cdot I(x, y)}{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} I(x, y)}, \\
88-
\bar{y} = \frac{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} y \cdot I(x, y)}{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} I(x, y)},
89-
$
77+
$$\bar{x} = \frac{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} x \cdot I(x, y)}{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} I(x, y)},$$
78+
$$\bar{y} = \frac{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} y \cdot I(x, y)}{\sum_{y=0}^{n-1} \sum_{x=0}^{m-1} I(x, y)}.$$
9079

91-
where $n$ is the total of rows, $m$ is the total of columns, $I(x, y) \in \{0, 1\}$ is the (binary, in this case) pixel intensity and $(x, y) \in [0, 512)^2$ is the pixel position.
80+
where $$n$$ is the total of rows, $$m$$ is the total of columns, $$I(x, y) \in \{0, 1\}$$ is the (binary, in this case) pixel intensity and $$(x, y) \in [0, 512)^2$$ is the pixel position.
9281

93-
```C++
82+
```cpp
9483
// Compute the centroid of the image
9584
const double* img_ptr = image.ptr<double>(0);
9685
double sumX{0.0}, sumY{0.0}, sumIntensity{0.0};
@@ -108,24 +97,24 @@ const double centroidX = sumX / sumIntensity;
10897
const double centroidY = sumY / sumIntensity;
10998
```
11099
111-
2. Now, we compute the shape dispersion matrix $M$ with the moments $m_{11}$ (second moment along the $x$-axis), $m_{22}$ (second moment along the $y$-axis), $m_{12}$ and $m_{21}$ (cross moments that represent correlations between $x$ and $y$):
100+
2. Now, we compute the shape dispersion matrix $$M$$ with the moments $$m_{11}$$ (second moment along the $$x$$-axis), $$m_{22}$$ (second moment along the $$y$$-axis), $$m_{12}$$ and $$m_{21}$$ (cross moments that represent correlations between $$x$$ and $$y$$):
112101
113-
$
102+
$$
114103
M =
115104
\begin{bmatrix}
116105
m_{11} & m_{12} \\
117106
m_{21} & m_{22}
118107
\end{bmatrix},
119-
$
108+
$$
120109
121110
where:
122-
$
111+
$$
123112
m_{11} = \frac{\sum_{y=0}^{N-1} \sum_{x=0}^{M-1} x^2 \cdot I(x, y)}{\sum_{y=0}^{N-1} \sum_{x=0}^{M-1} I(x, y)} - \bar{x}^2,
124113
m_{22} = \frac{\sum_{y=0}^{N-1} \sum_{x=0}^{M-1} y^2 \cdot I(x, y)}{\sum_{y=0}^{N-1} \sum_{x=0}^{M-1} I(x, y)} - \bar{y}^2,
125114
m_{12} = m_{21} = \frac{\sum_{y=0}^{N-1} \sum_{x=0}^{M-1} x \cdot y \cdot I(x, y)}{\sum_{y=0}^{N-1} \sum_{x=0}^{M-1} I(x, y)} - \bar{x} \cdot \bar{y}.
126-
$
115+
$$
127116
128-
```C++
117+
```cpp
129118
// Compute the moments m11, m22, m12 and m21
130119
double sum_m_11{0.0}, sum_m_22{0.0}, sum_m_12_m_21{0.0};
131120
for (int y = 0; y < totalRows; ++y)
@@ -148,8 +137,8 @@ cv::Mat M = (cv::Mat_<double>(2, 2) << m11, m12, m21, m22);
148137
149138
```
150139

151-
3. Compute the eigenvalues and eigenvectors of $M$:
152-
```C++
140+
3. Compute the eigenvalues and eigenvectors of $$M$$:
141+
```cpp
153142
cv::Mat eigenvalues, eigenvectors;
154143
cv::eigen(M, eigenvalues, eigenvectors);
155144
double lambda1 = eigenvalues.at<double>(0, 0);
@@ -158,14 +147,14 @@ cv::Vec2d E1(eigenvectors.at<double>(0, 0), eigenvectors.at<double>(1, 0));
158147
cv::Vec2d E2(eigenvectors.at<double>(0, 1), eigenvectors.at<double>(1, 1));
159148
```
160149
161-
4. Align the image with the _spectrum_ of $M$:
150+
4. Align the image with the _spectrum_ of $$M$$:
162151
To do this, we perform the following transformations:
163-
- Translate the origin to the centroid $(\bar{x}, \bar{y})$,
164-
- Rotate the axes to align with the eigenvectors of $M$,
165-
- Scale the axes according to the eigenvalues $\lambda_1$ and $\lambda_2$.
152+
- Translate the origin to the centroid $$(\bar{x}, \bar{y})$$,
153+
- Rotate the axes to align with the eigenvectors of $$M$$,
154+
- Scale the axes according to the eigenvalues $$\lambda_1$$ and $$\lambda_2$$.
166155
167-
To ensure that the area of the transformed image approximately matches the area of the input image (which may be of interest), we introduce an adaptive scaling factor $k$ based on the area of the character:
168-
```C++
156+
To ensure that the area of the transformed image approximately matches the area of the input image (which may be of interest), we introduce an adaptive scaling factor $$k$$ based on the area of the character:
157+
```cpp
169158
const int whitePixelCountOriginal = cv::countNonZero(image);
170159
171160
cv::Mat normalized;
@@ -264,8 +253,8 @@ We will understand the above code:
264253
* **Error Calculation**:
265254
After constructing the transformed image, the number of white pixels in the transformed image is compared (relative difference between areas) with the original number of white pixels.
266255

267-
* **Adjustment of Scaling Factor $k$**:
268-
If the transformed image's area is smaller than the original, $k$ is increased, otherwise $k$ is decreased. This brings transformed area closer to the original in each iteration.
256+
* **Adjustment of Scaling Factor $$k$$**:
257+
If the transformed image's area is smaller than the original, $$k$$ is increased, otherwise $$k$$ is decreased. This brings transformed area closer to the original in each iteration.
269258

270259
* **Stopping criteria**:
271260
The algorithm terminates when the error between the original and transformed image areas is below the specified tolerance, or when the maximum number of iterations is reached.

0 commit comments

Comments
 (0)