关于zxing识别中的源码
其中图像做二值化的部分
bool
GlobalHistogramBinarizer::getBlackRow(int y, BitArray& row) const //image处理的成员函数, y是所在行
{
int width = _source->width();
if (row.size() != width)
row = BitArray(width);
else
row.clearBits();
ByteArray buffer;
const uint8_t* luminances = _source->getRow(y, buffer); //获取一张图片第y行的数据
std::array<int, LUMINANCE_BUCKETS> buckets = {}; //static const int LUMINANCE_BUCKETS = 1 << 5;
for (int x = 0; x < width; x++) {
int pixel = luminances[x];
buckets[pixel >> LUMINANCE_SHIFT]++;
} //统计每一行像素点,0-255每8个单位为一个区间,类似作直方图
int blackPoint = EstimateBlackPoint(buckets);
if (blackPoint >= 0) {
if (width < 3) {
// Special case for very small images
for (int x = 0; x < width; x++) {
if (luminances[x] < blackPoint) {
row.set(x);
}
}
}
else {
if (luminances[0] < blackPoint)
row.set(0);
int left = luminances[0];
int center = luminances[1];
for (int x = 1; x < width - 1; x++) {
int right = luminances[x + 1];
// A simple -1 4 -1 box filter with a weight of 2.
//相当于在该行像素上做了-1 4 -1的滤波
if (((center * 4) - left - right) / 2 < blackPoint) {
row.set(x);
}
left = center;
center = right;
}
if (luminances[width-1] < blackPoint)
row.set(width-1);
}//二值化
return true;
}
return false;
}
static int EstimateBlackPoint(const std::array<int, LUMINANCE_BUCKETS>& buckets)
{
// Find the tallest peak in the histogram.
auto firstPeakPos = std::max_element(buckets.begin(), buckets.end()); //找到直方图的第一个peak
int firstPeak = static_cast<int>(firstPeakPos - buckets.begin());
int firstPeakSize = *firstPeakPos;
int maxBucketCount = firstPeakSize;
// Find the second-tallest peak which is somewhat far from the tallest peak.
int secondPeak = 0;
int secondPeakScore = 0;
for (int x = 0; x < LUMINANCE_BUCKETS; x++) {
int distanceToBiggest = x - firstPeak;
// Encourage more distant second peaks by multiplying by square of distance.
int score = buckets[x] * distanceToBiggest * distanceToBiggest;//第二个峰值与第一个峰值距离越大,size越大,得分越高,score = 区间像素总数*距离平方
if (score > secondPeakScore) {
secondPeak = x;
secondPeakScore = score;
}
}
// Make sure firstPeak corresponds to the black peak.
if (firstPeak > secondPeak) {
std::swap(firstPeak, secondPeak);
}
// If there is too little contrast in the image to pick a meaningful black point, throw rather
// than waste time trying to decode the image, and risk false positives.
//如果两个峰值太接近,则识别失败
if (secondPeak - firstPeak <= LUMINANCE_BUCKETS / 16) {
return -1;
}
// Find a valley between them that is low and closer to the white peak.
//在两个峰值之间找到第三个峰值,将这个峰值作为二值化的阈值
int bestValley = secondPeak - 1;
int bestValleyScore = -1;
for (int x = secondPeak - 1; x > firstPeak; x--) {
int fromFirst = x - firstPeak;
int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);
if (score > bestValleyScore) {
bestValley = x;
bestValleyScore = score;
}
}
return bestValley << LUMINANCE_SHIFT;
}