Ocean
QRCodeDetector2D.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #pragma once
9 
11 
15 
16 #if defined(OCEAN_QRCODES_QRCODEDEBUGELEMENTS_ENABLED)
18 #endif
19 
20 #include "ocean/base/Frame.h"
21 
22 #include "ocean/math/AnyCamera.h"
23 #include "ocean/math/Vector2.h"
24 
25 namespace Ocean
26 {
27 
28 namespace CV
29 {
30 
31 namespace Detector
32 {
33 
34 namespace QRCodes
35 {
36 
37 /**
38  * This class implements a detector for QR Codes.
39  * @ingroup cvdetectorqrcodes
40  */
41 class OCEAN_CV_DETECTOR_QRCODES_EXPORT QRCodeDetector2D : public QRCodeDetector
42 {
43  public:
44 
45  /**
46  * Definition of an observation of QR code in 2D
47  */
49  {
50  public:
51 
52  /**
53  * Creates an invalid observation
54  */
55  Observation() = default;
56 
57  /**
58  * Creates an valid observation
59  * @param code_T_camera The transformation that maps 3D coordinates in the QR code grid to the camera frame of reference, i.e., `imagePoint = anyCamera.projectToImage(code_T_camera, codePoint)`
60  * @param finderPatterns The three finder patterns of the QR Codes, elements must be in the order: top-left, bottom-left, top-right
61  */
62  inline explicit Observation(const HomogenousMatrix4& code_T_camera, FinderPatternTriplet&& finderPatterns);
63 
64  /**
65  * Returns if the observation is valid
66  * @return True if the observation is valid, otherwise false
67  */
68  inline bool isValid() const;
69 
70  /**
71  * Returns the transformation that maps coordinates in the QR code grid to coordinates in the reference frame of the camera
72  * @return The transformation
73  */
74  inline const HomogenousMatrix4& code_T_camera() const;
75 
76  /**
77  * Returns a pointer to the finder patterns
78  * @return The finder patterns
79  */
80  inline const FinderPatternTriplet& finderPatterns() const;
81 
82  protected:
83 
84  /// The transformation that maps 3D coordinates in the QR code grid to the camera frame of reference, i.e., `imagePoint = anyCamera.projectToImage(code_T_camera, codePoint)`
85  HomogenousMatrix4 code_T_camera_ = HomogenousMatrix4(false);
86 
87  /// The finder patterns of the QR code, order: top-left, bottom-left, top-right
89  };
90 
91  /// Definition of a vector of observations
92  typedef std::vector<Observation> Observations;
93 
94  public:
95 
96  /**
97  * Detects QR codes in an 8-bit grayscale image without lens distortion.
98  * Use this function for images without lens distortion, for example from pinhole cameras, screenshots, or similar.
99  * @param yFrame The frame in which QR codes will be detected, must be valid, have its origin in the upper left corner, and have a pixel format that is compatible with Y8, minimum size is 29 x 29 pixels
100  * @param observations Optional observations of the detected QR codes that will be returned, will be ignored for `nullptr`
101  * @param worker Optional worker instance for parallelization
102  * @param anyCamera The optionally returned camera profile that has been assumed internally
103  * @return The list of detected QR codes
104  */
105  static inline QRCodes detectQRCodes(const Frame& yFrame, Observations* observations = nullptr, Worker* worker = nullptr, SharedAnyCamera* anyCamera = nullptr);
106 
107  /**
108  * Detects QR codes in an 8-bit grayscale image with lens distortions
109  * Use this function for images with lens distortions, for example fisheye lenses on head-mounted devices (HMD). This requires a calibrated camera.
110  * @param anyCamera The camera profile that produced the input image, must be valid
111  * @param yFrame The frame in which QR codes will be detected, must be valid, match the camera size, have its origin in the upper left corner, and have a pixel format that is compatible with Y8, minimum size is 29 x 29 pixels
112  * @param observations Optional observations of the detected QR codes that will be returned, will be ignored for `nullptr`
113  * @param worker Optional worker instance for parallelization
114  * @return The list of detected QR codes
115  */
116  static inline QRCodes detectQRCodes(const AnyCamera& anyCamera, const Frame& yFrame, Observations* observations = nullptr, Worker* worker = nullptr);
117 
118  /**
119  * Detects QR codes in an 8-bit grayscale image
120  * @param anyCamera The camera profile that produced the input image, must be valid
121  * @param yFrame The frame in which QR codes will be detected, must be valid, match the camera size, have its origin in the upper left corner, and have a pixel format that is compatible with Y8
122  * @param width The width of the input frame, range: [29, infinity)
123  * @param height The height of the input frame, range: [29, infinity)
124  * @param paddingElements The number of padding elements of the input frame, range: [0, infinity)
125  * @param observations Optional observations of the detected QR codes that will be returned, will be ignored for `nullptr`
126  * @param worker Optional worker instance for parallelization
127  * @return The list of detected QR codes
128  */
129  static QRCodes detectQRCodes(const AnyCamera& anyCamera, const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, Observations* observations = nullptr, Worker* worker = nullptr);
130 };
131 
133  code_T_camera_(code_T_camera),
134  finderPatterns_(std::move(finderPatterns))
135 {
136  ocean_assert(isValid());
137 }
138 
140 {
141  return code_T_camera_.isValid() &&
142  // Finder pattern locations must be different
143  Numeric::isNotEqualEps(finderPatterns_[1].position().sqrDistance(finderPatterns_[0].position())) &&
144  Numeric::isNotEqualEps(finderPatterns_[2].position().sqrDistance(finderPatterns_[1].position())) &&
145  Numeric::isNotEqualEps(finderPatterns_[0].position().sqrDistance(finderPatterns_[2].position())) &&
146  // Ensure counter-clockwise order of the finder patterns
147  (finderPatterns_[1].position() - finderPatterns_[0].position()).cross(finderPatterns_[0].position() - finderPatterns_[2].position()) >= Scalar(0) &&
148  (finderPatterns_[2].position() - finderPatterns_[1].position()).cross(finderPatterns_[1].position() - finderPatterns_[0].position()) >= Scalar(0) &&
149  (finderPatterns_[0].position() - finderPatterns_[2].position()).cross(finderPatterns_[2].position() - finderPatterns_[1].position()) >= Scalar(0);
150 }
151 
153 {
154  return code_T_camera_;
155 }
156 
158 {
159  return finderPatterns_;
160 }
161 
162 inline QRCodes QRCodeDetector2D::detectQRCodes(const Frame& yFrame, Observations* observations, Worker* worker, SharedAnyCamera* sharedAnyCamera)
163 {
165  {
166  ocean_assert(false && "Frame must be valid and an 8 bit grayscale image and the pixel origin must be the upper left corner");
167  return QRCodes();
168  }
169 
170  Scalar fovX = Numeric::deg2rad(60);
171 
172  if (yFrame.height() > yFrame.width())
173  {
174  // Avoid large FOV values for pinhole cameras.
175  fovX = AnyCamera::fovY2X(fovX, Scalar(yFrame.width()) / Scalar(yFrame.height()));
176  }
177 
178  ocean_assert(fovX > Scalar(0));
179 
180  AnyCameraPinhole anyCamera(PinholeCamera(yFrame.width(), yFrame.height(), fovX));
181 
182  QRCodes codes = detectQRCodes(anyCamera, yFrame, observations, worker);
183 
184  if (sharedAnyCamera)
185  {
186  *sharedAnyCamera = std::make_shared<AnyCameraPinhole>(std::move(anyCamera));
187  }
188 
189  return codes;
190 }
191 
192 inline QRCodes QRCodeDetector2D::detectQRCodes(const AnyCamera& anyCamera, const Frame& yFrame, Observations* observations, Worker* worker)
193 {
195  {
196  ocean_assert(false && "Frame must be valid and an 8 bit grayscale image and the pixel origin must be the upper left corner");
197  return QRCodes();
198  }
199 
200  return detectQRCodes(anyCamera, yFrame.constdata<uint8_t>(), yFrame.width(), yFrame.height(), yFrame.paddingElements(), observations, worker);
201 }
202 
203 } // namespace QRCodes
204 
205 } // namespace Detector
206 
207 } // namespace CV
208 
209 } // namespace Ocean
This class implements the abstract base class for all AnyCamera objects.
Definition: AnyCamera.h:130
This class implements a specialized AnyCamera object wrapping the actual camera model.
Definition: AnyCamera.h:494
Definition of an observation of QR code in 2D.
Definition: QRCodeDetector2D.h:49
FinderPatternTriplet finderPatterns_
The finder patterns of the QR code, order: top-left, bottom-left, top-right.
Definition: QRCodeDetector2D.h:88
const FinderPatternTriplet & finderPatterns() const
Returns a pointer to the finder patterns.
Definition: QRCodeDetector2D.h:157
Observation()=default
Creates an invalid observation.
const HomogenousMatrix4 & code_T_camera() const
Returns the transformation that maps coordinates in the QR code grid to coordinates in the reference ...
Definition: QRCodeDetector2D.h:152
bool isValid() const
Returns if the observation is valid.
Definition: QRCodeDetector2D.h:139
This class implements a detector for QR Codes.
Definition: QRCodeDetector2D.h:42
std::vector< Observation > Observations
Definition of a vector of observations.
Definition: QRCodeDetector2D.h:92
static QRCodes detectQRCodes(const Frame &yFrame, Observations *observations=nullptr, Worker *worker=nullptr, SharedAnyCamera *anyCamera=nullptr)
Detects QR codes in an 8-bit grayscale image without lens distortion.
Definition: QRCodeDetector2D.h:162
static QRCodes detectQRCodes(const AnyCamera &anyCamera, const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, Observations *observations=nullptr, Worker *worker=nullptr)
Detects QR codes in an 8-bit grayscale image.
This class implements common functionality of QR code detectors but is not a stand-alone detector.
Definition: QRCodeDetector.h:33
static T fovY2X(const T fovY, const T aspectRatio)
Calculates the horizontal FOV from the vertical FOV and the aspect ratio of the camera image.
Definition: Camera.h:417
This class implements Ocean's image class.
Definition: Frame.h:1792
const T * constdata(const unsigned int planeIndex=0u) const
Returns a pointer to the read-only pixel data of a specific plane.
Definition: Frame.h:4168
bool isValid() const
Returns whether this frame is valid.
Definition: Frame.h:4448
unsigned int paddingElements(const unsigned int planeIndex=0u) const
Returns the optional number of padding elements at the end of each row for a specific plane.
Definition: Frame.h:4042
@ FORMAT_Y8
Pixel format for grayscale images with byte order Y and 8 bits per pixel.
Definition: Frame.h:594
unsigned int width() const
Returns the width of the frame format in pixel.
Definition: Frame.h:3143
PixelOrigin pixelOrigin() const
Returns the pixel origin of the frame.
Definition: Frame.h:3188
static bool arePixelFormatsCompatible(const PixelFormat pixelFormatA, const PixelFormat pixelFormatB)
Returns whether two given pixel formats are compatible.
PixelFormat pixelFormat() const
Returns the pixel format of the frame.
Definition: Frame.h:3153
@ ORIGIN_UPPER_LEFT
The first pixel lies in the upper left corner, the last pixel in the lower right corner.
Definition: Frame.h:1050
unsigned int height() const
Returns the height of the frame in pixel.
Definition: Frame.h:3148
static constexpr T deg2rad(const T deg)
Converts deg to rad.
Definition: Numeric.h:3232
static constexpr bool isNotEqualEps(const T value)
Returns whether a value is not smaller than or equal to a small epsilon.
Definition: Numeric.h:2237
This class implements a worker able to distribute function calls over different threads.
Definition: Worker.h:33
unsigned int sqrDistance(const char first, const char second)
Returns the square distance between two values.
Definition: base/Utilities.h:1089
std::array< FinderPattern, 3 > FinderPatternTriplet
Definition of a 3-tuple of finder patterns.
Definition: FinderPatternDetector.h:198
float Scalar
Definition of a scalar type.
Definition: Math.h:128
std::shared_ptr< AnyCamera > SharedAnyCamera
Definition of a shared pointer holding an AnyCamera object with Scalar precision.
Definition: AnyCamera.h:60
PinholeCameraT< Scalar > PinholeCamera
Definition of an pinhole camera object with Scalar precision.
Definition: PinholeCamera.h:32
HomogenousMatrixT4< Scalar > HomogenousMatrix4
Definition of the HomogenousMatrix4 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION flag eit...
Definition: HomogenousMatrix4.h:37
std::vector< QRCode > QRCodes
Definition of a vector of QR codes.
Definition: QRCode.h:25
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15