I did some more research and discovered
this article

I found that somone implemented this algorithim in opencv here

I then converted the code to the C++ opencv using Mats.

```
void ThinSubiteration1(Mat & pSrc, Mat & pDst) {
int rows = pSrc.rows;
int cols = pSrc.cols;
pSrc.copyTo(pDst);
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
if(pSrc.at<float>(i, j) == 1.0f) {
/// get 8 neighbors
/// calculate C(p)
int neighbor0 = (int) pSrc.at<float>( i-1, j-1);
int neighbor1 = (int) pSrc.at<float>( i-1, j);
int neighbor2 = (int) pSrc.at<float>( i-1, j+1);
int neighbor3 = (int) pSrc.at<float>( i, j+1);
int neighbor4 = (int) pSrc.at<float>( i+1, j+1);
int neighbor5 = (int) pSrc.at<float>( i+1, j);
int neighbor6 = (int) pSrc.at<float>( i+1, j-1);
int neighbor7 = (int) pSrc.at<float>( i, j-1);
int C = int(~neighbor1 & ( neighbor2 | neighbor3)) +
int(~neighbor3 & ( neighbor4 | neighbor5)) +
int(~neighbor5 & ( neighbor6 | neighbor7)) +
int(~neighbor7 & ( neighbor0 | neighbor1));
if(C == 1) {
/// calculate N
int N1 = int(neighbor0 | neighbor1) +
int(neighbor2 | neighbor3) +
int(neighbor4 | neighbor5) +
int(neighbor6 | neighbor7);
int N2 = int(neighbor1 | neighbor2) +
int(neighbor3 | neighbor4) +
int(neighbor5 | neighbor6) +
int(neighbor7 | neighbor0);
int N = min(N1,N2);
if ((N == 2) || (N == 3)) {
/// calculate criteria 3
int c3 = ( neighbor1 | neighbor2 | ~neighbor4) & neighbor3;
if(c3 == 0) {
pDst.at<float>( i, j) = 0.0f;
}
}
}
}
}
}
}
void ThinSubiteration2(Mat & pSrc, Mat & pDst) {
int rows = pSrc.rows;
int cols = pSrc.cols;
pSrc.copyTo( pDst);
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
if (pSrc.at<float>( i, j) == 1.0f) {
/// get 8 neighbors
/// calculate C(p)
int neighbor0 = (int) pSrc.at<float>( i-1, j-1);
int neighbor1 = (int) pSrc.at<float>( i-1, j);
int neighbor2 = (int) pSrc.at<float>( i-1, j+1);
int neighbor3 = (int) pSrc.at<float>( i, j+1);
int neighbor4 = (int) pSrc.at<float>( i+1, j+1);
int neighbor5 = (int) pSrc.at<float>( i+1, j);
int neighbor6 = (int) pSrc.at<float>( i+1, j-1);
int neighbor7 = (int) pSrc.at<float>( i, j-1);
int C = int(~neighbor1 & ( neighbor2 | neighbor3)) +
int(~neighbor3 & ( neighbor4 | neighbor5)) +
int(~neighbor5 & ( neighbor6 | neighbor7)) +
int(~neighbor7 & ( neighbor0 | neighbor1));
if(C == 1) {
/// calculate N
int N1 = int(neighbor0 | neighbor1) +
int(neighbor2 | neighbor3) +
int(neighbor4 | neighbor5) +
int(neighbor6 | neighbor7);
int N2 = int(neighbor1 | neighbor2) +
int(neighbor3 | neighbor4) +
int(neighbor5 | neighbor6) +
int(neighbor7 | neighbor0);
int N = min(N1,N2);
if((N == 2) || (N == 3)) {
int E = (neighbor5 | neighbor6 | ~neighbor0) & neighbor7;
if(E == 0) {
pDst.at<float>(i, j) = 0.0f;
}
}
}
}
}
}
}
void HandOCR::normalizeLetter(Mat & inputarray, Mat & outputarray) {
bool bDone = false;
int rows = inputarray.rows;
int cols = inputarray.cols;
inputarray.convertTo(inputarray,CV_32FC1);
inputarray.copyTo(outputarray);
outputarray.convertTo(outputarray,CV_32FC1);
/// pad source
Mat p_enlarged_src = Mat(rows + 2, cols + 2, CV_32FC1);
for(int i = 0; i < (rows+2); i++) {
p_enlarged_src.at<float>(i, 0) = 0.0f;
p_enlarged_src.at<float>( i, cols+1) = 0.0f;
}
for(int j = 0; j < (cols+2); j++) {
p_enlarged_src.at<float>(0, j) = 0.0f;
p_enlarged_src.at<float>(rows+1, j ...
```

(more)