typedef struct { BYTE b; BYTE g; BYTE r; } RGB; int calculateOtsuThreshold(const std::vector &grayscaleImage) { int histogram[256] = {0}; int totalPixels = grayscaleImage.size(); for (int i = 0; i < totalPixels; ++i) { histogram[grayscaleImage[i]]++; } float maxVariance = 0.0f; int threshold = 0; for (int t = 0; t < 256; ++t) { int w0 = 0; int w1 = 0; int sum0 = 0; int sum1 = 0; for (int i = 0; i < 256; ++i) { if (i <= t) { w0 += histogram[i]; sum0 += i * histogram[i]; } else { w1 += histogram[i]; sum1 += i * histogram[i]; } } float mean0 = (w0 == 0) ? 0 : static_cast(sum0) / w0; float mean1 = (w1 == 0) ? 0 : static_cast(sum1) / w1; float variance = static_cast(w0 * w1) * pow(mean0 - mean1, 2); if (variance > maxVariance) { maxVariance = variance; threshold = t; } } return threshold; } DECLARE_API bool otsu_binary(const void *image, int thresh) { auto imageptr = (uintptr_t)image; BITMAPFILEHEADER *fileHeader = (BITMAPFILEHEADER *)imageptr; imageptr += sizeof(BITMAPFILEHEADER); BITMAPINFOHEADER *infoHeader = (BITMAPINFOHEADER *)imageptr; imageptr += sizeof(BITMAPINFOHEADER); int height, weight; height = infoHeader->biHeight; weight = infoHeader->biWidth; if (infoHeader->biBitCount == 24) { int size = height * weight; RGB *img = (RGB *)imageptr; int threshold; if (thresh == -1) { std::vector grayscaleImage; for (int i = 0; i < size; i++) { grayscaleImage.push_back((BYTE)((img[i].r * 19595 + img[i].g * 38469 + img[i].b * 7472) >> 16)); } threshold = calculateOtsuThreshold(grayscaleImage); } else { threshold = thresh; } for (int i = 0; i < size; i++) { if ((BYTE)((img[i].r * 19595 + img[i].g * 38469 + img[i].b * 7472) >> 16) > threshold) { img[i].r = img[i].g = img[i].b = 255; } else { img[i].r = img[i].g = img[i].b = 0; } } return true; } else { return false; } }