// Adapted from "sizeOfBlackWhiteBlackRun" in zxing::qrcode::Detector Point QREdgeDetector::endOfReverseBlackWhiteBlackRun(const BitMatrix& image, Point from, Point to) { int fromX = (int)from.x; int fromY = (int)from.y; int toX = (int)to.x; int toY = (int)to.y; bool steep = abs(toY - fromY) > abs(toX - fromX); if (steep) { int temp = fromX; fromX = fromY; fromY = temp; temp = toX; toX = toY; toY = temp; } int dx = abs(toX - fromX); int dy = abs(toY - fromY); int error = -dx >> 1; int ystep = fromY < toY ? -1 : 1; int xstep = fromX < toX ? -1 : 1; int state = 0; // In black pixels, looking for white, first or second time // In case there are no points, prepopulate to from int realX = fromX; int realY = fromY; for (int x = fromX, y = fromY; x != toX; x += xstep) { realX = steep ? y : x; realY = steep ? x : y; if(realX < 0 || realY < 0 || realX >= (int)image.getWidth() || realY >= (int)image.getHeight()) break; if (state == 1) { // In white pixels, looking for black if (image.get(realX, realY)) { state++; } } else { if (!image.get(realX, realY)) { state++; } } if (state == 3) { // Found black, white, black, and stumbled back onto white; done return Point(realX, realY); } error += dy; if (error > 0) { y += ystep; error -= dx; } } // B-W-B run not found, return the last point visited. return Point(realX, realY); }
/** * Determines whether a segment contains a black point * * @param a min value of the scanned coordinate * @param b max value of the scanned coordinate * @param fixed value of fixed coordinate * @param horizontal set to true if scan must be horizontal, false if vertical * @return true if a black point has been found, else false. */ static bool ContainsBlackPoint(const BitMatrix& image, int a, int b, int fixed, bool horizontal) { if (horizontal) { for (int x = a; x <= b; x++) { if (image.get(x, fixed)) { return true; } } } else { for (int y = a; y <= b; y++) { if (image.get(fixed, y)) { return true; } } } return false; }
/** * <p>This method traces a line from a point in the image, in the direction towards another point. * It begins in a black region, and keeps going until it finds white, then black, then white again. * It reports the distance from the start to this point.</p> * * <p>This is used when figuring out how wide a finder pattern is, when the finder pattern * may be skewed or rotated.</p> */ static float SizeOfBlackWhiteBlackRun(const BitMatrix& image, int fromX, int fromY, int toX, int toY) { // Mild variant of Bresenham's algorithm; // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm bool steep = std::abs(toY - fromY) > std::abs(toX - fromX); if (steep) { std::swap(fromX, fromY); std::swap(toX, toY); } int dx = std::abs(toX - fromX); int dy = std::abs(toY - fromY); int error = -dx / 2; int xstep = fromX < toX ? 1 : -1; int ystep = fromY < toY ? 1 : -1; // In black pixels, looking for white, first or second time. int state = 0; // Loop up until x == toX, but not beyond int xLimit = toX + xstep; for (int x = fromX, y = fromY; x != xLimit; x += xstep) { int realX = steep ? y : x; int realY = steep ? x : y; // Does current pixel mean we have moved white to black or vice versa? // Scanning black in state 0,2 and white in state 1, so if we find the wrong // color, advance to next state or end if we are in state 2 already if ((state == 1) == image.get(realX, realY)) { if (state == 2) { return ResultPoint::Distance(x, y, fromX, fromY); } state++; } error += dy; if (error > 0) { if (y == toY) { break; } y += ystep; error -= dx; } } // Found black-white-black; give the benefit of the doubt that the next pixel outside the image // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. if (state == 2) { return ResultPoint::Distance(toX + xstep, toY, fromX, fromY); } // else we didn't find even black-white-black; no estimate is really possible return std::numeric_limits<float>::quiet_NaN(); }
ByteArray BitMatrixParser::ReadCodewords(const BitMatrix& image) { ByteArray result(144); int height = image.height(); int width = image.width(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int bit = BITNR[y][x]; if (bit >= 0 && image.get(x, y)) { result[bit / 6] |= static_cast<uint8_t>(1 << (5 - (bit % 6))); } } } return result; }
static bool GetBlackPointOnSegment(const BitMatrix& image, int aX, int aY, int bX, int bY, ResultPoint& result) { int dist = RoundToNearest(ResultPoint::Distance(aX, aY, bX, bY)); float xStep = static_cast<float>(bX - aX) / dist; float yStep = static_cast<float>(bY - aY) / dist; for (int i = 0; i < dist; i++) { int x = RoundToNearest(aX + i * xStep); int y = RoundToNearest(aY + i * yStep); if (image.get(x, y)) { result.set(static_cast<float>(x), static_cast<float>(y)); return true; } } return false; }
void findEdgePoints(std::vector<Point>& points, const BitMatrix& image, Point start, Point end, bool invert, int skip, float deviation) { float xdist = end.x - start.x; float ydist = end.y - start.y; float length = sqrt(xdist * xdist + ydist * ydist); int var; if (abs(xdist) > abs(ydist)) { // Horizontal if (xdist < 0) skip = -skip; var = int(abs(deviation * length / xdist)); float dy = ydist / xdist * skip; bool left = (skip < 0) ^ invert; int x = int(start.x); int steps = int(xdist / skip); for (int i = 0; i < steps; i++) { x += skip; if (x < 0 || x >= (int)image.getWidth()) continue; // In case we start off the edge int my = int(start.y + dy * i); int ey = min(my + var + 1, (int)image.getHeight() - 1); int sy = max(my - var, 0); for (int y = sy + 1; y < ey; y++) { if (left) { if (image.get(x, y) && !image.get(x, y + 1)) { points.push_back(Point(x, y + 0.5f)); } } else { if (!image.get(x, y) && image.get(x, y + 1)) { points.push_back(Point(x, y + 0.5f)); } } } } } else { // Vertical if (ydist < 0) skip = -skip; var = int(abs(deviation * length / ydist)); float dx = xdist / ydist * skip; bool down = (skip > 0) ^ invert; int y = int(start.y); int steps = int(ydist / skip); for (int i = 0; i < steps; i++) { y += skip; if (y < 0 || y >= (int)image.getHeight()) continue; // In case we start off the edge int mx = int(start.x + dx * i); int ex = min(mx + var + 1, (int)image.getWidth() - 1); int sx = max(mx - var, 0); for (int x = sx + 1; x < ex; x++) { if (down) { if (image.get(x, y) && !image.get(x + 1, y)) { points.push_back(Point(x + 0.5f, y)); } } else { if (!image.get(x, y) && image.get(x + 1, y)) { points.push_back(Point(x + 0.5f, y)); } } } } } }