728x90

머신 비전 기반 PCB(Printed Circuit Board) 자동 광학 검사(AOI) 시스템은 결함 탐지 정확성을 극대화하려면 세심한 조정이 필수적이다. 해당 시스템에서는 고강도 레이저와 마이크로미터 단위 해상도를 제공하는 고정밀 카메라를 사용하여 회로 기판의 사진을 촬영한다. 본 예에서는 Halcon 라이브러리를 이용해 분석한 PCB 사진에서 결함을 성공적으로 식별했다.

 

결함 탐지 과정에서 발생 가능한 두 가지 주요 오류는 '언더킬'(감지되지 않은 결함)과 '오버킬'(잘못 감지된 결함)이다. 언더킬은 시스템이 실제 결함을 감지하지 못하는 경우, 오버킬은 없는 결함을 잘못 감지하는 경우를 말한다. 목표는 언더킬을 완전히 제거하여 모든 결함을 정확히 식별하고, 오버킬을 최소화하는 것이다.

 

이 목표를 달성하기 위해 결정 임계값(Threshold)의 조정이 중요하다. 임계값 조정을 통해 시스템은 결함 있는 것으로 판단된 사례들을 'Defect' 폴더와 'Overkill' 폴더로 분류할 수 있다. 추가로, 초점이 맞지 않는 사진은 'Focus Out' 폴더로 분류되어야 한다.

 

결함 탐지 시스템의 최적화를 위해 발견된 결함 유형별로 세분화하는 패턴 분류가 중요하다. 이는 검사 과정의 정확도를 높이고, 오버킬의 수를 줄이는 데 기여하며, 결함 탐지 알고리즘의 지속적 개선을 가능하게 한다. 이러한 접근 방식은 PCB 제조 과정의 품질 관리를 향상시키고, 최종 제품의 신뢰성을 보장하는 데 필수적이다.

 

11389개의 파일을 패턴별로 나뉘어야 분류가 최적화된다.

일단 Teachable Machine사이트에 접속해서 이미지 > 삽입된 이미지 모델로 들어가준다. 그레이스케일 이미지에 적합하기 때문이다. 각 패턴별로 이미지들을 학습시켜야 한다. 100장 정도만 학습시켜도 충분해 보인다. 테스팅의 일반적인 원리에서 결함 집중(Defect clustering)이라는 게 있는데 이는 대다수의 결함들은 소수의 특정 모듈에 집중된다는 뜻이다. 결함 집중 느낌처럼 특정 결함은 특정 패턴에서만 자주 일어나 분류를 최적화하기 위하여 패턴별로 폴더를 나누는 것이다.

Class1에는 focus out defect가 자주 일어나는 패턴이고 Class2는 overkill이 자주 일어나는 패턴이다.

그리고 학습을 시키고 테스트를 해보다가 모델 내보내기를 하여 코드를 받아준다.

이 코드를 vs code에 가져와 폴더를 옮길 수 있는 라이브러리를 정의하고

import os

import shutil

사진을 입력받는 란을 만들어 주고받은 사진을 정의하는 함수를 만든 뒤, 이런 식으로 바꿔주면 된다.

async function predict() {

if(prediction[0].className == "Class1" && prediction[0].probability.toFixed(2) >= 0.80) {

shutil.move("/경로/입력받은 사진 파일을 정의한 함수","/경로/옮겨줄 폴더"}

if(prediction[0].className == "Class2" && prediction[0].probability.toFixed(2) >= 0.80) {

shutil.move("/경로/입력받은 사진 파일을 정의한 함수","/경로/옮겨줄 폴더"}

}

0.80은 학습된 파일과 입력된 사진이 80% 일치하면 이라는 뜻이다. threshold처럼 조정하며 이용하면 된다.

728x90
728x90
 

사이트에 들어가면 이미지 프로젝트, 오디오 프로젝트, 포즈 프로젝트가 있다. 포즈 프로젝트는 홈트 할 때 가벼운 게임 정도 만들면 좋을 것 같다. 이미지 프로젝트에는 표준 이미지 모델과 삽입된 이미지 모델이 있는데 그레이스케일 이미지가 있는 것 보니까 opencv, halcon 등 영상처리 프로그래밍 관련에 어울리는 인터페이스인 것 같다.

캠으로 실시간으로 러닝을 시킬 수 있고 저장된 파일을 업로드하여 러닝을 시킬 수도 있다. 전부 학습시켰으면 모델 학습시키기 버튼을 눌러 학습을 시키고 모델 내보내기를 하여 러닝된 값을 주소화시켜서 제공받거나 프로그램 형태로 다운로드할 수 있다.

나는 검은 바나나와 흰 바나나 두 개를 학습시켰다.

그리고 프로그램에 뜨는 퍼센티지를 활용하여 과일 등급을 선정해 주게 일부 코드를 변경하였다. 아이디어만 많으면 다양하게 코드 활용이 가능해 보인다.

리팩토링된 풀 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>Teachable Machine Image Model</div>
    <button type="button" onclick="init()">Start</button>
    <div id="webcam-container"></div>
    <div id="label-container"></div>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@0.8/dist/teachablemachine-image.min.js"></script>
    <script type="text/javascript">
        const URL = "./my_model/";

        let model, webcam, labelContainer, maxPredictions;

        async function init() {
            const modelURL = URL + "model.json";
            const metadataURL = URL + "metadata.json";

            model = await tmImage.load(modelURL, metadataURL);
            maxPredictions = model.getTotalClasses();

            const flip = true; // whether to flip the webcam
            webcam = new tmImage.Webcam(200, 200, flip);
            await webcam.setup(); // request access to the webcam
            await webcam.play();
            window.requestAnimationFrame(loop);

            document.getElementById("webcam-container").appendChild(webcam.canvas);
            labelContainer = document.getElementById("label-container");
            for (let i = 0; i < maxPredictions; i++) {
                labelContainer.appendChild(document.createElement("div"));
            }
        }

        async function loop() {
            webcam.update(); // update the webcam frame
            await predict();
            window.requestAnimationFrame(loop);
        }

        async function predict() {
            const prediction = await model.predict(webcam.canvas);
            const probability = prediction[0].probability.toFixed(2);
            const className = prediction[0].className;
            
            let grade = "D급 입니다."; // Default to D grade
            if (className == "pure") {
                if (probability >= 0.99) {
                    grade = "A급 입니다.";
                } else if (probability >= 0.50) {
                    grade = "B급 입니다.";
                } else if (probability > 0) {
                    grade = "C급 입니다.";
                }
            }

            labelContainer.childNodes[0].innerHTML = grade;
        }
    </script>
</body>
</html>

이렇게 앱, 웹 등 다양하게 확인이 가능하다.

사과를 학습 안시키고 돌려보았다.

 

728x90

'인공지능' 카테고리의 다른 글

Teachable Machine를 이용한 검출력 사진 분류  (1) 2024.03.22

+ Recent posts