diff --git a/src/types/opencv/QRCodeDetector.ts b/src/types/opencv/QRCodeDetector.ts new file mode 100644 index 0000000..a71f9d7 --- /dev/null +++ b/src/types/opencv/QRCodeDetector.ts @@ -0,0 +1,111 @@ +import type { + bool, + InputArray, + InputOutputArray, + OutputArray, + OutputArrayOfArrays, + Point2f, +} from "./_types"; + +/** + * QR Code detection and decoding class. + * + * This class implements QR code detection and decoding functionality. + * It can detect QR codes in an image and decode their content. + * + * Source: + * [opencv2/objdetect.hpp](https://github.com/opencv/opencv/tree/master/modules/objdetect/include/opencv2/objdetect.hpp). + */ +export declare class QRCodeDetector { + /** + * QRCodeDetector constructor + */ + public constructor(); + + /** + * Detects QR code in image and returns the quadrangle containing the code. + * + * @param img grayscale or color (BGR) image containing (or not) QR code. + * @param points Output vector of vertices of the minimum-area quadrangle containing the code. + */ + public detect(img: InputArray, points: OutputArray): bool; + + /** + * Decodes QR code in image once it's found by the detect() method. + * + * @param img grayscale or color (BGR) image containing QR code. + * @param points Quadrangle vertices found by detect() method (or some other algorithm). + * @param straight_qrcode The optional output image containing rectified and binarized QR code + */ + public decode( + img: InputArray, + points: InputArray, + straight_qrcode?: OutputArray + ): String; + + /** + * Both detects and decodes QR code + * + * @param img grayscale or color (BGR) image containing QR code. + * @param points optional output array of vertices of the found QR code quadrangle. Will be empty if not found. + * @param straight_qrcode The optional output image containing rectified and binarized QR code + */ + public detectAndDecode( + img: InputArray, + points?: OutputArray, + straight_qrcode?: OutputArray + ): String; + + /** + * Detects QR codes in image and returns the vector of the quadrangles containing the codes. + * + * @param img grayscale or color (BGR) image containing (or not) QR codes. + * @param points Output vector of vector of vertices of the minimum-area quadrangle containing the codes. + */ + public detectMulti(img: InputArray, points: OutputArrayOfArrays): bool; + + /** + * Decodes QR codes in image once it's found by the detectMulti() method. + * + * @param img grayscale or color (BGR) image containing QR codes. + * @param points vector of Quadrangle vertices found by detectMulti() method (or some other algorithm). + * @param decoded_info UTF8-encoded output vector of String or empty vector of String if the codes cannot be decoded. + * @param straight_qrcode The optional output vector of images containing rectified and binarized QR codes + */ + public decodeMulti( + img: InputArray, + points: InputArray, + decoded_info: any, + straight_qrcode?: OutputArrayOfArrays + ): bool; + + /** + * Both detects and decodes QR codes + * + * @param img grayscale or color (BGR) image containing QR codes. + * @param decoded_info UTF8-encoded output vector of String or empty vector of String if the codes cannot be decoded. + * @param points optional output vector of vertices of the found QR code quadrangles. Will be empty if not found. + * @param straight_qrcode The optional output vector of images containing rectified and binarized QR codes + */ + public detectAndDecodeMulti( + img: InputArray, + decoded_info: any, + points?: OutputArrayOfArrays, + straight_qrcode?: OutputArrayOfArrays + ): bool; + + /** + * Aruco-based QR code detector + */ + public setUseAruco(use_aruco: bool): void; + + /** + * Get if Aruco-based QR code detector is used + */ + public getUseAruco(): bool; + + /** + * Releases the object + */ + public delete(): void; +} \ No newline at end of file diff --git a/src/types/opencv/QRCodeDetectorAruco.ts b/src/types/opencv/QRCodeDetectorAruco.ts new file mode 100644 index 0000000..706c4a3 --- /dev/null +++ b/src/types/opencv/QRCodeDetectorAruco.ts @@ -0,0 +1,139 @@ +import type { + bool, + float, + InputArray, + OutputArray, + OutputArrayOfArrays, +} from "./_types"; + +/** + * Parameters for QRCodeDetectorAruco + */ +export declare class QRCodeDetectorAruco_Params { + public minModuleSizeInPyramid: float; + public maxRotation: float; + public maxModuleSizeMismatch: float; + public maxTimingPatternMismatch: float; + public maxPenalties: float; + public maxColorsMismatch: float; + public scaleTimingPatternScore: float; + + public constructor(); + + /** + * Releases the object + */ + public delete(): void; +} + +/** + * QR Code detection and decoding class using Aruco-based detection. + * + * This class implements QR code detection and decoding functionality using + * Aruco marker detection techniques for improved robustness. + * + * Source: + * [opencv2/objdetect.hpp](https://github.com/opencv/opencv/tree/master/modules/objdetect/include/opencv2/objdetect.hpp). + */ +export declare class QRCodeDetectorAruco { + /** + * QRCodeDetectorAruco constructor + */ + public constructor(); + + /** + * QRCodeDetectorAruco constructor with parameters + * + * @param params QRCodeDetectorAruco parameters + */ + public constructor(params: QRCodeDetectorAruco_Params); + + /** + * Detects QR code in image and returns the quadrangle containing the code. + * + * @param img grayscale or color (BGR) image containing (or not) QR code. + * @param points Output vector of vertices of the minimum-area quadrangle containing the code. + */ + public detect(img: InputArray, points: OutputArray): bool; + + /** + * Decodes QR code in image once it's found by the detect() method. + * + * @param img grayscale or color (BGR) image containing QR code. + * @param points Quadrangle vertices found by detect() method (or some other algorithm). + * @param straight_qrcode The optional output image containing rectified and binarized QR code + */ + public decode( + img: InputArray, + points: InputArray, + straight_qrcode?: OutputArray + ): String; + + /** + * Both detects and decodes QR code + * + * @param img grayscale or color (BGR) image containing QR code. + * @param points optional output array of vertices of the found QR code quadrangle. Will be empty if not found. + * @param straight_qrcode The optional output image containing rectified and binarized QR code + */ + public detectAndDecode( + img: InputArray, + points?: OutputArray, + straight_qrcode?: OutputArray + ): String; + + /** + * Detects QR codes in image and returns the vector of the quadrangles containing the codes. + * + * @param img grayscale or color (BGR) image containing (or not) QR codes. + * @param points Output vector of vector of vertices of the minimum-area quadrangle containing the codes. + */ + public detectMulti(img: InputArray, points: OutputArrayOfArrays): bool; + + /** + * Decodes QR codes in image once it's found by the detectMulti() method. + * + * @param img grayscale or color (BGR) image containing QR codes. + * @param points vector of Quadrangle vertices found by detectMulti() method (or some other algorithm). + * @param decoded_info UTF8-encoded output vector of String or empty vector of String if the codes cannot be decoded. + * @param straight_qrcode The optional output vector of images containing rectified and binarized QR codes + */ + public decodeMulti( + img: InputArray, + points: InputArray, + decoded_info: any, + straight_qrcode?: OutputArrayOfArrays + ): bool; + + /** + * Both detects and decodes QR codes + * + * @param img grayscale or color (BGR) image containing QR codes. + * @param decoded_info UTF8-encoded output vector of String or empty vector of String if the codes cannot be decoded. + * @param points optional output vector of vertices of the found QR code quadrangles. Will be empty if not found. + * @param straight_qrcode The optional output vector of images containing rectified and binarized QR codes + */ + public detectAndDecodeMulti( + img: InputArray, + decoded_info: any, + points?: OutputArrayOfArrays, + straight_qrcode?: OutputArrayOfArrays + ): bool; + + /** + * Get detector parameters + */ + public getDetectorParameters(): QRCodeDetectorAruco_Params; + + /** + * Set detector parameters + * + * @param params QRCodeDetectorAruco parameters + */ + public setDetectorParameters(params: QRCodeDetectorAruco_Params): void; + + /** + * Releases the object + */ + public delete(): void; +} \ No newline at end of file diff --git a/src/types/opencv/objdetect.ts b/src/types/opencv/objdetect.ts index 5b8be12..2d870b3 100644 --- a/src/types/opencv/objdetect.ts +++ b/src/types/opencv/objdetect.ts @@ -101,3 +101,6 @@ export declare const CASCADE_SCALE_IMAGE: any; // initializer: = 2 export declare const CASCADE_FIND_BIGGEST_OBJECT: any; // initializer: = 4 export declare const CASCADE_DO_ROUGH_SEARCH: any; // initializer: = 8 + +export { QRCodeDetector } from "./QRCodeDetector"; +export { QRCodeDetectorAruco, QRCodeDetectorAruco_Params } from "./QRCodeDetectorAruco"; diff --git a/test/QRCodeDetector.test.ts b/test/QRCodeDetector.test.ts new file mode 100644 index 0000000..76e1453 --- /dev/null +++ b/test/QRCodeDetector.test.ts @@ -0,0 +1,253 @@ +import { Jimp } from "jimp"; +import path from "path"; +import { setupOpenCv } from "./cv"; + +beforeAll(async () => { + await setupOpenCv(); +}); + +describe("QRCodeDetector", () => { + it("should be available as a class", () => { + expect(cv.QRCodeDetector).toBeDefined(); + expect(typeof cv.QRCodeDetector).toBe("function"); + }); + + it("should be able to create QRCodeDetector instance", () => { + const detector = new cv.QRCodeDetector(); + expect(detector).toBeDefined(); + expect(detector.constructor.name).toBe("QRCodeDetector"); + }); + + it("should have detect method", () => { + const detector = new cv.QRCodeDetector(); + expect(detector.detect).toBeDefined(); + expect(typeof detector.detect).toBe("function"); + }); + + it("should have decode method", () => { + const detector = new cv.QRCodeDetector(); + expect(detector.decode).toBeDefined(); + expect(typeof detector.decode).toBe("function"); + }); + + it("should have detectAndDecode method", () => { + const detector = new cv.QRCodeDetector(); + expect(detector.detectAndDecode).toBeDefined(); + expect(typeof detector.detectAndDecode).toBe("function"); + }); + + it("should have detectMulti method", () => { + const detector = new cv.QRCodeDetector(); + expect(detector.detectMulti).toBeDefined(); + expect(typeof detector.detectMulti).toBe("function"); + }); + + it("should have decodeMulti method", () => { + const detector = new cv.QRCodeDetector(); + expect(detector.decodeMulti).toBeDefined(); + expect(typeof detector.decodeMulti).toBe("function"); + }); + + it("should have detectAndDecodeMulti method", () => { + const detector = new cv.QRCodeDetector(); + expect(detector.detectAndDecodeMulti).toBeDefined(); + expect(typeof detector.detectAndDecodeMulti).toBe("function"); + }); + + it("should be able to clean up detector", () => { + const detector = new cv.QRCodeDetector(); + // Just verify we can call delete without errors + expect(() => detector.delete()).not.toThrow(); + }); + + it("should detect and decode QR code from image", async () => { + const detector = new cv.QRCodeDetector(); + + try { + // Load the test QR code image + const jimpSrc = await Jimp.read(path.resolve(__dirname, "test-qr.png")); + const img = cv.matFromImageData(jimpSrc.bitmap); + + // Convert RGBA to BGR as OpenCV expects BGR format + const imgBGR = new cv.Mat(); + cv.cvtColor(img, imgBGR, cv.COLOR_RGBA2BGR); + + // Test detectAndDecode method + const points = new cv.Mat(); + const decodedText = detector.detectAndDecode(imgBGR, points); + + // Verify the decoded text matches what we encoded + expect(decodedText).toBe("Hello OpenCV.js QR Test!"); + + // Verify points were detected (should have 4 corner points) + expect(points.rows).toBeGreaterThan(0); + expect(points.cols).toBeGreaterThan(0); + + // Clean up + img.delete(); + imgBGR.delete(); + points.delete(); + } finally { + detector.delete(); + } + }); + + it("should detect QR code corners using detect method", async () => { + const detector = new cv.QRCodeDetector(); + + try { + // Load the test QR code image + const jimpSrc = await Jimp.read(path.resolve(__dirname, "test-qr.png")); + const img = cv.matFromImageData(jimpSrc.bitmap); + + // Convert RGBA to BGR as OpenCV expects BGR format + const imgBGR = new cv.Mat(); + cv.cvtColor(img, imgBGR, cv.COLOR_RGBA2BGR); + + // Test detect method + const points = new cv.Mat(); + const detected = detector.detect(imgBGR, points); + + // Verify QR code was detected + expect(detected).toBe(true); + expect(points.rows).toBeGreaterThan(0); + expect(points.cols).toBeGreaterThan(0); + + // Clean up + img.delete(); + imgBGR.delete(); + points.delete(); + } finally { + detector.delete(); + } + }); + + it("should decode previously detected QR code using decode method", async () => { + const detector = new cv.QRCodeDetector(); + + try { + // Load the test QR code image + const jimpSrc = await Jimp.read(path.resolve(__dirname, "test-qr.png")); + const img = cv.matFromImageData(jimpSrc.bitmap); + + // Convert RGBA to BGR as OpenCV expects BGR format + const imgBGR = new cv.Mat(); + cv.cvtColor(img, imgBGR, cv.COLOR_RGBA2BGR); + + // First detect the QR code + const points = new cv.Mat(); + const detected = detector.detect(imgBGR, points); + expect(detected).toBe(true); + + // Then decode it using the detected points + const decodedText = detector.decode(imgBGR, points); + expect(decodedText).toBe("Hello OpenCV.js QR Test!"); + + // Clean up + img.delete(); + imgBGR.delete(); + points.delete(); + } finally { + detector.delete(); + } + }); +}); + +describe("QRCodeDetectorAruco", () => { + it("should be available as a class", () => { + expect(cv.QRCodeDetectorAruco).toBeDefined(); + expect(typeof cv.QRCodeDetectorAruco).toBe("function"); + }); + + it("should be able to create QRCodeDetectorAruco instance", () => { + const detector = new cv.QRCodeDetectorAruco(); + expect(detector).toBeDefined(); + expect(detector.constructor.name).toBe("QRCodeDetectorAruco"); + }); + + it("should have detect method", () => { + const detector = new cv.QRCodeDetectorAruco(); + expect(detector.detect).toBeDefined(); + expect(typeof detector.detect).toBe("function"); + }); + + it("should have decode method", () => { + const detector = new cv.QRCodeDetectorAruco(); + expect(detector.decode).toBeDefined(); + expect(typeof detector.decode).toBe("function"); + }); + + it("should have detectAndDecode method", () => { + const detector = new cv.QRCodeDetectorAruco(); + expect(detector.detectAndDecode).toBeDefined(); + expect(typeof detector.detectAndDecode).toBe("function"); + }); + + it("should be able to clean up detector", () => { + const detector = new cv.QRCodeDetectorAruco(); + // Just verify we can call delete without errors + expect(() => detector.delete()).not.toThrow(); + }); + + it("should detect and decode QR code from image using Aruco detector", async () => { + const detector = new cv.QRCodeDetectorAruco(); + + try { + // Load the test QR code image + const jimpSrc = await Jimp.read(path.resolve(__dirname, "test-qr.png")); + const img = cv.matFromImageData(jimpSrc.bitmap); + + // Convert RGBA to BGR as OpenCV expects BGR format + const imgBGR = new cv.Mat(); + cv.cvtColor(img, imgBGR, cv.COLOR_RGBA2BGR); + + // Test detectAndDecode method + const points = new cv.Mat(); + const decodedText = detector.detectAndDecode(imgBGR, points); + + // Verify the decoded text matches what we encoded + expect(decodedText).toBe("Hello OpenCV.js QR Test!"); + + // Verify points were detected + expect(points.rows).toBeGreaterThan(0); + expect(points.cols).toBeGreaterThan(0); + + // Clean up + img.delete(); + imgBGR.delete(); + points.delete(); + } finally { + detector.delete(); + } + }); +}); + +describe("QRCodeDetectorAruco_Params", () => { + it("should be available as a class", () => { + expect(cv.QRCodeDetectorAruco_Params).toBeDefined(); + expect(typeof cv.QRCodeDetectorAruco_Params).toBe("function"); + }); + + it("should be able to create QRCodeDetectorAruco_Params instance", () => { + const params = new cv.QRCodeDetectorAruco_Params(); + expect(params).toBeDefined(); + expect(params.constructor.name).toBe("QRCodeDetectorAruco_Params"); + }); + + it("should have expected properties", () => { + const params = new cv.QRCodeDetectorAruco_Params(); + expect(params.minModuleSizeInPyramid).toBeDefined(); + expect(params.maxRotation).toBeDefined(); + expect(params.maxModuleSizeMismatch).toBeDefined(); + expect(params.maxTimingPatternMismatch).toBeDefined(); + expect(params.maxPenalties).toBeDefined(); + expect(params.maxColorsMismatch).toBeDefined(); + expect(params.scaleTimingPatternScore).toBeDefined(); + }); + + it("should be able to clean up params", () => { + const params = new cv.QRCodeDetectorAruco_Params(); + // Just verify we can call delete without errors + expect(() => params.delete()).not.toThrow(); + }); +}); \ No newline at end of file diff --git a/test/test-qr.png b/test/test-qr.png new file mode 100644 index 0000000..97c9faf Binary files /dev/null and b/test/test-qr.png differ