Contact Lens Defect Inspection A manufacturing defect affecting cylinder power triggered an FDA recall of nearly 34,000 contact lenses last year. Roboflow published a tutorial showing how to train an object detection model on a public dataset of lens images labeled for cracks and bubbles, then build a workflow that flags uncertain cases for human review. A manufacturing https://roboflow.com/industries/manufacturing?ref=blog.roboflow.com defect impacting cylinder power was enough to trigger an FDA recall of close to 34,000 https://www.thehealthy.com/eye-care/news-contact-lens-recall/?ref=blog.roboflow.com contact lenses last year. On a line running through millions of lenses a year, a defect https://roboflow.com/ai/defect?ref=blog.roboflow.com doesn't have to be common to matter; it just has to slip past inspection. A trapped air bubble or a hairline crack can be nearly invisible under normal lighting, and a human eye won't catch every one, every time. When a labeled dataset already exists for a defect type, the most direct path is to train a model on it. This tutorial does exactly that: it takes a public dataset of contact lens images labeled for cracks and bubbles, trains an object detection model with Roboflow https://roboflow.com/?ref=blog.roboflow.com , and builds a around it that doesn't just say pass or fail, it flags uncertain cases for a person to review. https://docs.roboflow.com/workflows/what-is-workflows?ref=blog.roboflow.com Workflow By the end, you'll have a trained model and a working Workflow that takes a single lens image and returns one of three outcomes: pass, review, or fail, along with the image showing exactly what it found. Contact Lens Defect Inspection with Vision AI Go to Roboflow Universe https://universe.roboflow.com/?ref=blog.roboflow.com and search for the . With over 250,000 open source datasets on Universe, there's a good chance someone has already collected and labeled images close to your use case. https://universe.roboflow.com/conference-ezgcv/contact-lens-defect-detection?ref=blog.roboflow.com contact lens defect detection dataset This one contains contact lens images shot under dark-field illumination, annotated for two defect types: crack hairline fractures in the lens material and bubble trapped air pockets . Lighting intensity, defect size, and position relative to the lens center all vary across the set, exactly the kind of spread a model needs to see before it encounters real production images. From here, fork the dataset into your own workspace, annotations included, so you have your own copy to build on. Build the Workflow Here's the workflow we'll build https://app.roboflow.com/workflows/embed/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3b3JrZmxvd0lkIjoiTmRnTEpGd09MWXo1dzNXcWhMdnYiLCJ3b3Jrc3BhY2VJZCI6Im5JRk5DOGRjbU5OOXZ4d29ybWpoWTdCNjdQZTIiLCJ1c2VySWQiOiJuSUZOQzhkY21OTjl2eHdvcm1qaFk3QjY3UGUyIiwiaWF0IjoxNzgxNTI1Mzc4fQ.xqA4VmHgUu1 s1g qVUARN4PlX2 nWP2Cfd4Yep32JE?ref=blog.roboflow.com , and here's what each block does in this Workflow. Object Detection Model: runs the trained RF-DETR model on the image and returns a bounding box for any detected crack or bubble, each with a confidence score. Bounding Box Visualization: draws those boxes on the image. Label Visualization: adds the class name to each box. Custom Python Block: reads the detections and sorts the result into pass, review, or fail based on confidence. Text Display: writes the result onto the image. Roboflow Vision Events: logs each inspection, image, detection, and result for monitoring. Outputs: returns the labeled image and a JSON report. Step 1: Generate a dataset version and train RF-DETR In your forked project, go to the Versions tab and generate a new version. Apply augmentation: Flip horizontal and vertical , 90° Rotate CW, CCW, 180° , and Rotation ±15° . These multiply the training images without distorting what a crack or bubble looks like. Once the version is generated, click Custom Train and select RF-DETR https://blog.roboflow.com/rf-detr/ Small , Roboflow's real-time object detection model. Training runs through Roboflow's hosted training pipeline, no local setup or GPU to manage. When training finishes, review the metrics on the test set: mAP https://blog.roboflow.com/mean-average-precision/ , , https://blog.roboflow.com/precision-and-recall/ :~:text=Machine%20Learning%20Video-,What%20is%20Precision%3F,-What%20can%20we precision , and https://blog.roboflow.com/precision-and-recall/ :~:text=will%20waste%20water.-,What%20is%20Recall,-%3F%20What%20does%20Recall recall . These reflect how the model performs on images it never saw during training. https://blog.roboflow.com/f1-score/ F1 This turns a small, pre-labeled dataset into a working detector, ready to plug into a Workflow. Step 2: Add the trained model as an Object Detection block Open the Workflows tab and create a new Workflow. Roboflow adds an Image Input and Outputs block automatically. Click the plus icon, search for Object Detection Model, and add it as defect detector. Connect the image to inputs.image, then copy the model URL from your trained model's card and paste it into the Model field to select the version from Step 1. Set the confidence threshold to 0.4, lower than the 0.6 cutoff used later to decide pass, review, or fail. Anything the model detects with at least 40% confidence gets passed downstream, including borderline detections in the 40-60% range, which the next block routes to review instead of discarding. This block returns a bounding box and confidence score for each crack or bubble it finds above 0.4. What happens next, pass, review, or fail, depends on those confidence scores, handled by the Custom Python Block coming up. Step 3: Add Bounding Box and Label Visualization Add a Bounding Box Visualization block. Connect Image to inputs.image and Predictions to defect detector.predictions. This draws a box around each detected crack or bubble. Add a Label Visualization block right after it. Connect Image to the bounding box block's output, and Predictions to defect detector.predictions again. This adds the class name crack or bubble next to each box. At this point, the image shows exactly what the model found and where; the next steps decide what that means for the result. Step 4: Add the Custom Python Block triage logic Add a Custom Python Block named "Quality Check". Connect one input, predictions, to defect detector.predictions, kind object detection prediction. Add three outputs: report dictionary , display text string , and qc result string . Click Edit Code to open the full editor, where you can also add a description, e.g., "Generate a pass/fail quality inspection report for contact lens crack and bubble defects," and write the code: python def run self, predictions : 1. Collect detections that match our defect classes, with confidence defect classes = {"crack", "bubble"} found = if predictions is not None: try: class names = predictions.data.get "class name", confidences = predictions.confidence for name, conf in zip class names, confidences : if str name .lower in defect classes: found.append {"defect": str name , "confidence": float conf } except Exception: pass 2. Decide pass/review / fail based on the highest confidence found if not found: status = "PASS" else: max conf = max d "confidence" for d in found if max conf = 0.6: status = "FAIL" else: status = "REVIEW" 3. Build the human-readable summary no confidence numbers shown if found: defect names = sorted set d "defect" for d in found defect list = ", ".join defect names else: defect list = "None" display text = f"Status: {status}\nDefects: {defect list}" 4. Package everything for the rest of the Workflow report = { "status": status, "defects": found, "defect count": len found , } return { "report": report, "display text": display text, "qc result": status } Open the full editor: This is where the actual decision happens: no detection above 0.4 means pass, a detection below 0.6 confidence means review, and 0.6 or higher means fail. display text carries the version shown on the image, without confidence numbers, while report keeps the full detail. Step 5: Add Text Display Add a Text Display block. Connect Image to label visualization.image, the output of the visualization chain from Step 3, and connect Text to quality check.display text. Set the style to white text on a semi-transparent black background, anchored to the bottom-left corner, consistent with the rest of the image. The image now shows both the detected boxes from Step 3 and the pass, review, or fail result from Step 4, all in one frame. Step 6: Add Vision Events and configure Outputs Add a Roboflow Vision Events https://docs.roboflow.com/deploy/vision-events?ref=blog.roboflow.com block. Connect its input image to the original image, its output image to the Text Display result, predictions to the detector's output, and the quality result to the Quality Check block's status output. This logs every inspection, the original image, the labeled result, what was detected, and the final status, without changing what the Workflow returns. Finally, set the Outputs: the output image comes from Text Display, and the quality report comes from the Quality Check block's report. With that, the Workflow is complete: one image in, a labeled image, and a structured report out, with every run logged for later review. Step 7: Configure Outputs Set two outputs: the output image from Text Display, and the quality report from the Quality Check block's report. With everything connected, the full Workflow looks like this: From here, every image that comes in gets a labeled result, a structured report, and a logged record, no extra steps needed. Contact Lens Defect Inspection Results Test case 1: Clean lens, status pass A lens with no visible cracks or bubbles returns an empty defects list and a pass status. This represents the ideal case on the production line: a standard pass with no defects or missing components detected. Test case 2: Two low-confidence detections, status review Two potential bubble defects are identified, but both fall below the 0.6 confidence cutoff. As a result, the case is sent for review rather than being automatically accepted or rejected. Both detections are legitimate findings, but with insufficient confidence for an automatic pass/fail decision. The review tier preserves that uncertainty instead of forcing a result that doesn't reflect what the model actually observed. Test case 3: Bubble and crack, status fail A bubble and a crack are detected in the same lens. With one or more detections above the confidence cutoff, the image is automatically classified as a fail, and both defects are reported. Both defect types are captured in the same inspection result, ensuring that reviewers see the full set of findings without needing to inspect separate outputs. Production Deployment The 0.6 cutoff reflects a handful of test images, and the review queue is what refines it from here. Each REVIEW image is a borderline case: once a person checks it, add it back to the dataset on Roboflow Universe and include it in the next training run. The more borderline cases the model sees, the fewer it needs a person for. Vision Events records every inspection: the lens, what was detected, and the final call. Aggregated across a shift or lot, that becomes a defect rate you can break down by lot number, station, or time of day, useful for catching a faulty mold cavity or an inconsistent light source before it affects more units. The same Workflow runs through Roboflow's API https://docs.roboflow.com/developer/rest-api/using-the-rest-api?ref=blog.roboflow.com or on-device with , so it can sit at multiple points on the line, after molding, before packaging, without changes. Every station returns the same pass, review, or fail format, ready to feed into whatever tracks the batch. https://inference.roboflow.com/?ref=blog.roboflow.com Roboflow Inference Build It Faster with the Roboflow Agent If you'd rather not add each block by hand, use Roboflow Agent https://app.roboflow.com/solutions/chat/new?ref=blog.roboflow.com . Instead of configuring blocks one at a time, you describe the pipeline you want in plain text and the Agent builds it for you. Here's an example: Contact Lens Defect Inspection Conclusion This Workflow takes a single contact lens image, runs it through a custom-trained RF-DETR https://rfdetr.roboflow.com/latest/?ref=blog.roboflow.com model, and returns one of three outcomes: pass, review, or fail, along with the image showing exactly what was found. No manual rules, no separate inspection step, and no forced choice between a hard pass/fail gate and human oversight, the Workflow handles both. What makes this durable is that none of it is fixed. The confidence threshold, the defect classes, and even the dataset itself can keep changing as production images come in; each REVIEW case is a candidate for the next training run. The Workflow doesn't need to be rebuilt to get better; the model underneath it does. The same structure extends well beyond contact lenses: fork a dataset for any defect type, train a model, and plug it into this Workflow. The detection block changes, the triage logic, visualization, and logging stay the same. Further reading: Cite this Post Use the following entry to cite this post in your research: Mostafa Ibrahim /author/mostafa/ . Jun 16, 2026 . Contact Lens Defect Inspection. Roboflow Blog: https://blog.roboflow.com/contact-lens-defect-inspection/