Add AR Overlays in MatrixScan
Prerequisites
To proceed, you need to setup a project that uses MatrixScan first, check out this guide (you can ignore the bottom section about the visualization of tracked barcodes using SDCBarcodeTrackingBasicOverlay).
Getting started
There are two ways to add advanced AR overlays to a Data Capture View:
Take advantage of the SDCBarcodeTrackingAdvancedOverlay class, which provides a ready-to-use implementation for view-based AR overlays.
Provide your own custom implementation, using the function SDCBarcodeTrackingListener.barcodeTracking:didUpdate:frameData: to retrieve the barcode’s current screen position for each frame.
Note
The first way is the easiest, as it takes care of adding, removing and animating the overlay’s views whenever needed. It’s also flexible enough to cover the majority of use cases.
You can always handle touch events on the views you create like you normally would.
Using BarcodeTrackingAdvancedOverlay
As mentioned above, the advanced overlay combined with its listener offers an easy way of adding augmentations to your SDCDataCaptureView. In this guide we will add a view above each barcode showing its content.
First of all, create a new instance of SDCBarcodeTrackingAdvancedOverlay and add it to the SDCDataCaptureView.
let overlay = BarcodeTrackingAdvancedOverlay(barcodeTracking: barcodeTracking, for: captureView)
At this point, you have two options.
Add a SDCBarcodeTrackingAdvancedOverlayDelegate to the overlay.
Use the setters in the overlay to specify the view, anchor and offset for each barcode.
Note
The second way will take priority over the first one, which means that if a view for a barcode has been set using SDCBarcodeTrackingAdvancedOverlay.setView:forTrackedBarcode:, the function SDCBarcodeTrackingAdvancedOverlayDelegate.barcodeTrackingAdvancedOverlay:viewForTrackedBarcode: won’t be invoked for that specific barcode.
Using SDCBarcodeTrackingAdvancedOverlayDelegate
You need to conform to SDCBarcodeTrackingAdvancedOverlayDelegate. This protocol’s methods are invoked every time a barcode is newly tracked.
SDCBarcodeTrackingAdvancedOverlayDelegate.barcodeTrackingAdvancedOverlay:viewForTrackedBarcode: asks for a view to animate on top of the barcode. Returning nil will show no view.
SDCBarcodeTrackingAdvancedOverlayDelegate.barcodeTrackingAdvancedOverlay:anchorForTrackedBarcode: asks how to anchor the view to the barcode through SDCAnchor. Be aware that it anchors the view’s center to the anchor point. To achieve anchoring the top of the view or the bottom etc. you will have to set an offset as explained in the next point.
SDCBarcodeTrackingAdvancedOverlayDelegate.barcodeTrackingAdvancedOverlay:offsetForTrackedBarcode: asks for an offset that is applied on the already anchored view. This offset is expressed through a SDCPointWithUnit.
func barcodeTrackingAdvancedOverlay(_ overlay: BarcodeTrackingAdvancedOverlay,
viewFor trackedBarcode: TrackedBarcode) -> UIView? {
// Create and return the view you want to show for this tracked barcode. You can also return nil, to have no view for this barcode.
let label = UILabel()
label.text = trackedBarcode.barcode.data
label.backgroundColor = .white
label.sizeToFit()
return label
}
func barcodeTrackingAdvancedOverlay(_ overlay: BarcodeTrackingAdvancedOverlay,
anchorFor trackedBarcode: TrackedBarcode) -> Anchor {
// As we want the view to be above the barcode, we anchor the view's center to the top-center of the barcode quadrilateral.
// Use the function below to adjust the position of the view by providing an offset.
return .topCenter
}
func barcodeTrackingAdvancedOverlay(_ overlay: BarcodeTrackingAdvancedOverlay,
offsetFor trackedBarcode: TrackedBarcode) -> PointWithUnit {
// This is the offset that will be applied to the view.
// You can use .fraction to give a measure relative to the view itself, the sdk will take care of transforming this into pixel size.
// We now center horizontally and move up the view to make sure it's centered and above the barcode quadrilateral by half of the view's height.
return PointWithUnit(
x: FloatWithUnit(value: 0, unit: .fraction),
y: FloatWithUnit(value: -1, unit: .fraction)
)
}
Using the setters in the overlay
The function SDCBarcodeTrackingListener.barcodeTracking:didUpdate:frameData: gives you access to a session, which contains all added, updated and removed tracked barcodes. From here you can create the view you want to display, and then call SDCBarcodeTrackingAdvancedOverlay.setView:forTrackedBarcode:, SDCBarcodeTrackingAdvancedOverlay.setAnchor:forTrackedBarcode: and SDCBarcodeTrackingAdvancedOverlay.setOffset:forTrackedBarcode:
func barcodeTracking(_ barcodeTracking: BarcodeTracking,
didUpdate session: BarcodeTrackingSession,
frameData: FrameData) {
DispatchQueue.main.async {
for trackedBarcode in session.addedTrackedBarcodes {
let label = UILabel()
label.text = trackedBarcode.barcode.data
label.backgroundColor = .white
label.sizeToFit()
self.overlay.setView(label, for: trackedBarcode)
self.overlay.setAnchor(.topCenter, for: trackedBarcode)
let point = PointWithUnit(x: FloatWithUnit(value: 0, unit: .fraction),
y: FloatWithUnit(value: -1, unit: .fraction))
self.overlay.setOffset(point, for: trackedBarcode)
}
}
}
Provide your own custom implementation
If you do not want to use the overlay, it is also possible to add augmented reality features based on the tracking identifier and the quadrilateral coordinates that every tracked barcode has. Below are some pointers.
Set a SDCBarcodeTrackingListener on the barcode tracking
In the SDCBarcodeTrackingListener.barcodeTracking:didUpdate:frameData: function fetch the added and removed tracked barcodes.
Create and show the views for the added barcodes.
Remove the views for the lost barcodes.
Add a method that is called 60fps when SDCBarcodeTracking is enabled. In this method, for each SDCTrackedBarcode on-screen, update the position based on SDCTrackedBarcode.location. Please note that there is no need to animate the change of location, the change of position will happen frequently enough that the view will look as it is animated.
The best way to have a method called 60fps, is by using CADisplayLink.
Note
The frame coordinates from SDCTrackedBarcode.location need to be mapped to view coordinates, using SDCDataCaptureView.viewQuadrilateralForFrameQuadrilateral:.
func barcodeTracking(_ barcodeTracking: BarcodeTracking,
didUpdate session: BarcodeTrackingSession,
frameData: FrameData) {
DispatchQueue.main.async {
for lostTrackIdentifier in session.removedTrackedBarcodes {
// You now know the identifier of the tracked barcode that has been lost. Usually here you would remove the views associated.
}
for trackedBarcode in session.addedTrackedBarcodes {
// Fixed identifier for the tracked barcode.
let trackingIdentifier = trackedBarcode.identifier
// Current location of the tracked barcode.
let location = trackedBarcode.location
let quadrilateral = self.captureView.viewQuadrilateral(forFrameQuadrilateral: location)
// You now know this new tracking's identifier and location. Usually here you would create and show the views.
}
}
}