{"slug": "contact-lens-defect-inspection", "title": "Contact Lens Defect Inspection", "summary": "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.", "body_md": "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\n\n[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.\n\nA 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.\n\nThis 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\n\n[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)\n\n__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.\n\n## Contact Lens Defect Inspection with Vision AI\n\nGo to [ Roboflow Universe](https://universe.roboflow.com/?ref=blog.roboflow.com) and search for the\n\n[. 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)\n\n__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).\n\nLighting 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.\n\nFrom here, fork the dataset into your own workspace, annotations included, so you have your own copy to build on.\n\n### Build the Workflow\n\n[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.\n\n**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.\n\n### Step 1: Generate a dataset version and train RF-DETR\n\nIn 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.\n\nOnce 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.\n\nWhen training finishes, review the metrics on the test set: [ mAP](https://blog.roboflow.com/mean-average-precision/),\n\n[,](https://blog.roboflow.com/precision-and-recall/#:~:text=Machine%20Learning%20Video-,What%20is%20Precision%3F,-What%20can%20we)\n\n__precision__[, and](https://blog.roboflow.com/precision-and-recall/#:~:text=will%20waste%20water.-,What%20is%20Recall,-%3F%20What%20does%20Recall)\n\n__recall__[. These reflect how the model performs on images it never saw during training.](https://blog.roboflow.com/f1-score/)\n\n__F1__This turns a small, pre-labeled dataset into a working detector, ready to plug into a Workflow.\n\n### Step 2: Add the trained model as an Object Detection block\n\nOpen the Workflows tab and create a new Workflow. Roboflow adds an Image Input and Outputs block automatically.\n\nClick 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.\n\nSet 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.\n\nThis 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.\n\n### Step 3: Add Bounding Box and Label Visualization\n\nAdd 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.\n\nAdd 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.\n\nAt this point, the image shows exactly what the model found and where; the next steps decide what that means for the result.\n\n### Step 4: Add the Custom Python Block (triage logic)\n\nAdd 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).\n\nClick 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:\n\n``` python\ndef run(self, predictions):\n    # 1. Collect detections that match our defect classes, with confidence\n    defect_classes = {\"crack\", \"bubble\"}\n    found = []\n    if predictions is not None:\n        try:\n            class_names = predictions.data.get(\"class_name\", [])\n            confidences = predictions.confidence\n            for name, conf in zip(class_names, confidences):\n                if str(name).lower() in defect_classes:\n                    found.append({\"defect\": str(name), \"confidence\": float(conf)})\n        except Exception:\n            pass\n    # 2. Decide pass/review / fail based on the highest confidence found\n    if not found:\n        status = \"PASS\"\n    else:\n        max_conf = max(d[\"confidence\"] for d in found)\n        if max_conf >= 0.6:\n            status = \"FAIL\"\n        else:\n            status = \"REVIEW\"\n    # 3. Build the human-readable summary (no confidence numbers shown)\n    if found:\n        defect_names = sorted(set(d[\"defect\"] for d in found))\n        defect_list = \", \".join(defect_names)\n    else:\n        defect_list = \"None\"\n    display_text = f\"Status: {status}\\nDefects: {defect_list}\"\n    # 4. Package everything for the rest of the Workflow\n    report = {\n        \"status\": status,\n        \"defects\": found,\n        \"defect_count\": len(found),\n    }\n    return {\n        \"report\": report,\n        \"display_text\": display_text,\n        \"qc_result\": status\n    }\n```\n\nOpen the full editor:\n\nThis 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.\n\n### Step 5: Add Text Display\n\nAdd 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.\n\nThe image now shows both the detected boxes from Step 3 and the pass, review, or fail result from Step 4, all in one frame.\n\n### Step 6: Add Vision Events and configure Outputs\n\nAdd 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.\n\nThis logs every inspection, the original image, the labeled result, what was detected, and the final status, without changing what the Workflow returns.\n\nFinally, set the Outputs: the output image comes from Text Display, and the quality report comes from the Quality Check block's report.\n\nWith that, the Workflow is complete: one image in, a labeled image, and a structured report out, with every run logged for later review.\n\n### Step 7: Configure Outputs\n\nSet two outputs: the output image from Text Display, and the quality report from the Quality Check block's report.\n\nWith everything connected, the full Workflow looks like this:\n\nFrom here, every image that comes in gets a labeled result, a structured report, and a logged record, no extra steps needed.\n\n## Contact Lens Defect Inspection Results\n\n### Test case 1: Clean lens, status pass\n\nA lens with no visible cracks or bubbles returns an empty defects list and a pass status.\n\nThis represents the ideal case on the production line: a standard pass with no defects or missing components detected.\n\n### Test case 2: Two low-confidence detections, status review\n\nTwo 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.\n\nBoth 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.\n\n### Test case 3: Bubble and crack, status fail\n\nA 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.\n\nBoth defect types are captured in the same inspection result, ensuring that reviewers see the full set of findings without needing to inspect separate outputs.\n\n## Production Deployment\n\nThe 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.\n\nVision 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.\n\nThe 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\n\n[, 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)\n\n__Roboflow Inference__## Build It Faster with the Roboflow Agent\n\nIf 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:\n\n## Contact Lens Defect Inspection Conclusion\n\nThis 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.\n\nWhat 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.\n\nThe 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.\n\nFurther reading:\n\n**Cite this Post**\n\nUse the following entry to cite this post in your research:\n\n[Mostafa Ibrahim](/author/mostafa/). (Jun 16, 2026).\nContact Lens Defect Inspection. Roboflow Blog: https://blog.roboflow.com/contact-lens-defect-inspection/", "url": "https://wpnews.pro/news/contact-lens-defect-inspection", "canonical_source": "https://blog.roboflow.com/contact-lens-defect-inspection/", "published_at": "2026-06-16 16:39:06+00:00", "updated_at": "2026-06-16 16:56:59.171710+00:00", "lang": "en", "topics": ["computer-vision", "ai-products", "ai-tools"], "entities": ["Roboflow", "FDA", "RF-DETR", "Roboflow Universe"], "alternates": {"html": "https://wpnews.pro/news/contact-lens-defect-inspection", "markdown": "https://wpnews.pro/news/contact-lens-defect-inspection.md", "text": "https://wpnews.pro/news/contact-lens-defect-inspection.txt", "jsonld": "https://wpnews.pro/news/contact-lens-defect-inspection.jsonld"}}