getBlackMatrix() {
			if (this.matrix !== null) {
				return this.matrix;
			}
			const source = this.getLuminanceSource();
			const width = source.getWidth();
			const height = source.getHeight();
			if (width >= HybridBinarizer.MINIMUM_DIMENSION && height >= HybridBinarizer.MINIMUM_DIMENSION) {
				const luminances = source.getMatrix();
				let subWidth = width >> HybridBinarizer.BLOCK_SIZE_POWER;
				if ((width & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) {
					subWidth++;
				}
				let subHeight = height >> HybridBinarizer.BLOCK_SIZE_POWER;
				if ((height & HybridBinarizer.BLOCK_SIZE_MASK) !== 0) {
					subHeight++;
				}
				const blackPoints = HybridBinarizer.calculateBlackPoints(luminances, subWidth, subHeight, width, height);
				const newMatrix = new BitMatrix(width, height);
				HybridBinarizer.calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix);
				this.matrix = newMatrix;
			}
			else {
				// If the image is too small, fall back to the global histogram approach.
				this.matrix = super.getBlackMatrix();
			}
			return this.matrix;
		}
Calculates the final BitMatrix once for all requests. This could be called once from the
constructor instead, but there are some advantages to doing it lazily, such as making
profiling easier, and not doing heavy lifting when callers don't expect it.