티스토리 뷰

IT

opencv를 이용한 QR코드 인식

msna 2024. 10. 11. 18:10

결론

  • ZXing으로 QR코드가 인식이 잘 안될 때 opencv라는 선택지도 있다.
  • opencv는 라이브러리 설정이 필요하다.

 

개요

  • ZXing을 이용해 이미지 파일에서 QR코드를 인식하고 있었지만, 가끔 제대로 인식이 되지 않음
  • 아마도 이미지 파일이 스캔한 결과물이라 인쇄가 잘못되었던가, 스캔할 때 의 하얀 먼지일 걸로 예상

 

문제가 된 이미지

  • 왼쪽 위의 검은 사각형 안에 흰 부분이 있다.

 

대응안

  • 기존 ZXing에 TRY_HARDER옵션이 있는데 그 옵션을 활성화:  실패
    • 위의 이미지에 대한 결과가 없음
  • QR인식 전의 이미지 방식을 변경: 실패
    • ZXing이용시 byte[] → BufferedImage → BufferedImageLuminanceSource → HybridBinarizer →BinaryBitmap순으로 데이터가 변환이 되는데, 중간 단계의 구현체를 변경해보기로 함. 그러나 개선되지 않음.
  • 다른 QR인식 라이브러리 사용: 성공
    • 인터넷에서 검색해보면 자바에서는 ZXing가 대부분이나 opencv라는 라이브러리로도 QR인식이 가능해 도입해보기로 함.

 

opencv도입하기

  • pom.xml에 opencv추가
<!-- https://mvnrepository.com/artifact/org.openpnp/opencv -->
<dependency>
    <groupId>org.openpnp</groupId>
    <artifactId>opencv</artifactId>
    <version>4.9.0-0</version>
</dependency>
  • maven 로컬 저장위치에서 현재 사용중인 OS에 맞는 라이브러리를 빼내서 이동
  • pom.xml에서 라이브러리를 저장한 패스를 java.library.path으로 설정.
    전체적으로 이용하는 공통 라이브러리 디렉토리가 있는게 아니고 모듈별로 바뀔 수 있기 때문에 pom.xml에서 설정하도록 하였다.
    <build>
      <plugins>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
              <systemPropertyVariables>
                <java.library.path>${project.basedir}/../library</java.library.path>
              </systemPropertyVariables>
            </configuration>
        </plugin>
      </plugins>
    </build>
  • QR코드 인식 코드
    import javax.imageio.ImageIO;
    import java.io.File;
    import org.opencv.objdetect.QRCodeDetector;
    
    // 라이브러리 로드가 필요하다. 1번만 하면 되므로 static처리
    static{
      System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
    }
    
    BufferedImage bufferedImage;
    String format = "tiff";
    File tempFile = File.createTempFile("temp", "." + format);
    ImageIO.write(bufferedImage, format, tempFile);
    
    QRCodeDetector qrCodeDetector = new QRCodeDetector();
    
    // Imgcodecs.imread의 결과는 Mat이라는 클래스인데,
    // 여기서는 파일로 읽었지만 byte배열로도 만드는 방법도 있다.
    // 나중에 중간단계 파일이 필요할지도 몰라서 파일로 처리하였다.
    
    String qrResult = qrCodeDetector.detectAndDecode(Imgcodecs.imread(tempFile.getAbsolutePath()));
    // qrResult는 인식이 되지 않으면 ""으로 온다.
    
    tempFile.delete();