FireMonkey Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
FireMonkey 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
델마당
볼랜드포럼 광고 모집

FireMonkey 팁&트릭
[23] ZXing.Delphi 바코드 스캔 예제 소스
박지훈.임프 [cbuilder] 3838 읽음    2016-06-20 01:56
DemoBarcodeReader_win32.zip 2.7MB 윈도우 데모 실행파일
DemoBarcodeReader.apk 8MB 안드로이드 데모 APK
앞서 바코드 스캔 라이브러리 ZXing.Delphi에 대한 소개와 버그 수정에 대한 포스트를 올렸는데요. 이번에는 이 라이브러리를 제대로 사용하기 위한 예제 프로젝트에 대해 설명해보겠습니다.

원론적으로 보면, ZXing.Delphi 라이브러리의 사용법 자체는 꽤 간단합니다.

1. 먼저 TScanManager 객체를 생성해놓습니다.
2. 카메라를 액티브시킨 후, TCameraComponent의 OnSampleBufferReady 이벤트가 발생되면 이벤트 핸들러를 통해 카메라 캡쳐 이미지를 비트맵으로 받습니다.
3. 캡쳐된 비트맵을 TScanManager.Scan() 함수로 넘깁니다.
4. TScanManager.Scan() 함수의 리턴값(TReadResult 타입)을 받아 그 안에 인식된 바코드 값이 담겨 있으면 인식이 성공한 경우입니다.
(실제로는 동기화를 위한 코드가 더 추가되는 등 조금 더 복잡합니다)

물론 ZXing.Delphi의 배포 소스에도 이런 과정을 보여주는 데모 프로젝트가 포함되어 있습니다. 그런데 이 데모 프로젝트는 실제로 사용하기에는 완성도가 좀 떨어져서, ZXing.Delphi의 뛰어난 성능을 제대로 보여주지 못합니다. 그래서 실무 프로젝트에 적용할 수 있을 정도로 개선된 데모 프로젝트를 만들어봤습니다.

원래의 데모 프로젝트보다 개선된 주요 사항들은 다음과 같습니다.

1. 캡쳐 Quality를 MediumQuality로 설정하는 코드를 수정했습니다.

QR 코드 스캔 목적으로는 최고 해상도가 아닌 미디엄만 해도 충분하고 캡쳐 속도도 빠르기 때문에 원본 데모 소스에서도 카메라 컴포넌트의 Quality 속성을 MediumQuality로 지정하고 있었는데요. Firemonkey의 이 Quality 속성에는 약간의 버그가 있어서 제대로 값이 설정되지 않는 경우가 있습니다. 이에 대해서는 앞서 올린 글을 참고하시기 바랍니다.
http://delphi.borlandforum.com/impboard/impboard.dll?action=read&db=del_tip&no=350
CameraComponent1.Quality := TVideoCaptureQuality.HighQuality;
CameraComponent1.Quality := TVideoCaptureQuality.MediumQuality;

2. 카메라 컴포넌트에서 넘어온 비트맵을 잘라내도록 코드를 추가했습니다.

QR코드는 형태가 정사각형이고 다른 1차원 바코드들은 가로로 길쭉한 형태이기 때문에, 세로(혹은 가로)로 길쭉한 카메라 스캔 이미지는 바코드 인식을 위한 이미지로는 적합하지 않습니다. 또 스캔할 이미지에 바코드 이외에 다른 이미지가 함께 찍히면 그만큼 인식률이 떨어져 여러번, 더 긴 시간동안 스캔을 시도해야만 하게 됩니다. 특히 스캔 대상에 바코드가 여러개 연속되어 있는 경우에는 원하는 바코드가 아닌 엉뚱한 바코드가 함께 찍혀 딴 것이 먼저 인식되거나, 다른 바코드의 이미지 일부 때문에 인식 실패가 발생하는 경우도 잦습니다. 따라서 일반적으로 스캔할 이미지는 길쭉한 형태보다는 정사각형에 가까워 스캔 대상 이미지가 그 안에 가득 찰수 있도록 해주는 편이 스캔 인식이 훨씬 잘 됩니다.

그래서, 카메라 이미지를 바로 ScanManager로 넘기는 대신 프리뷰 이미지의 크기에 맞춰(정확하게는 가로세로 비율만 맞춰) 아래위를 잘라낸(crop) 비트맵을 전달하도록 코드를 추가했습니다. 이렇게 적절한 크기로 잘라냈을 때 스캔 인식률은, 잘라내지 않은 카메라 이미지를 그대로 스캔 시도할 때보다 현저하게 좋아집니다. (반드시 정사각형이어야 할 필요까지는 없지만 정사각형에 가까운 편이 좋습니다) 물론 비트맵을 한번 더 복사하는 작업이 들어가서 약간 느려지는 부분도 있지만, 잘라낸 만큼 스캔할 비트맵 데이터가 작아지므로 바코드 스캔 속도는 전보다 훨씬 빨라집니다. 실제 테스트를 해보면 잘라내지 않았을 때보다 몇배나 빠르게 바코드를 인식할 수 있습니다.
  tempBitmap := TBitmap.Create;
  try
    CameraComponent1.SampleBufferToBitmap(tempBitmap, True);
    iNewHeight := Trunc(tempBitmap.Width * imgCamera.Size.Height / imgCamera.Size.Width);
    ARect := Rect(0, (tempBitmap.Height-iNewHeight) div 2, tempBitmap.Width, tempBitmap.Height - (tempBitmap.Height-iNewHeight) div 2);
    imgCamera.Bitmap.SetSize(ARect.Width, ARect.Height);
    imgCamera.Bitmap.CopyFromBitmap(tempBitmap, ARect, 0, 0);
  finally
    tempBitmap.Free;
  end;


이와 더불어, 원래의 데모 소스에서는 프리뷰 이미지의 WrapMode가 Stretch로 되어 있었던 것을 Fit로 수정했습니다. 사실 이미지의 가로세로 비율에 맞게 비트맵을 잘라냈으므로 Fit로 하든 Stretch로 하든 사용자의 눈에 보이는 결과는 차이가 없겠습니다만.

3. 지속적인 오토포커스를 하도록 했습니다.

TCameraComponent.FocusMode의 기본값은 AutoFocus입니다. ContinuousAutoFocus 값은 원래 움직이는 피사체를 대상으로 계속 포커스를 시도하는 모드인데, 바코드 스캔 동작 중에는 사용자가 카메라를 계속 움직이는 것이 당연하므로 AutoFocus보다 ContinuousAutoFocus가 훨씬 낫습니다. 당연히 인식 속도가 빨라집니다.
CameraComponent1.FocusMode := TFocusMode.ContinuousAutoFocus;


4. 화면 Orientation을 Portrait로 고정시켰습니다.

앱의 화면이 자동회전 되면 위 2번 항목의 변경으로 가로세로 크기를 맞춰놓은 프리뷰 이미지 때문에 화면 레이아웃이 의도한 것과 다르게 이상하게 될 수밖에 없습니다. 따라서 디자인 단계에서 Portrait나 Ladscape 어느쪽으로든 Orientation을 고정시키는 것이 낫습니다.

5. 카메라가 없는 윈도우 PC에서 바코드 이미지를 불러들여 테스트하는 코드를 추가했습니다(Windows).

개발 테스트 및 디버깅 편의를 위해 추가한 것으로, Load Test 버튼을 누르면 OpenDialog로 바코드가 포함된 이미지를 선택해서 불러들여 바코드 인식을 할 수 있습니다. 한편 모바일에는 OpenDialog가 없으므로 모바일인 경우 로드 버튼이 나타나지 않도록 했습니다. (안드로이드 플랫폼에 오픈다이얼로그 기능이 없기 때문에, 코드상으로는 컴포넌트를 배치하고 기능 호출도 가능하지만 실제 다이얼로그가 뜨지 않습니다)

6. QR코드를 인식했을 때 Toast 메시지를 뿌리도록 코드를 추가했습니다(Android).

사소한 것이지만, 바코드가 인식되었을 때 명확하게 알려주기 위한 것입니니다. 토스트가 지원되지 않는 안드로이드 이외 플랫폼(Windows, iOS)에서는 ShowMessage로 나타납니다.

참고: 스캔을 시작하는 클래스인 TScanManager의 생성자의 첫번째 인자가 인식할 바코드의 포맷 종류인데요. 데모 코드에서는 TBarcodeFormat.Auto로서, 이 라이브러리가 인식 가능한 모든 바코드를 다 인식하도록 하는 옵션입니다. 짐작하시겠지만, 인식할 코드 종류의 수가 많을수록 인식 속도가 그만큼 느려집니다. 따라서 QR Code나 Code 128처럼 특정 코드를 인식하려는 대부분의 경우에는 Auto가 아니라 해당 코드 포맷을 지정하는 것이 좋습니다. (물론 저도 데모가 아닌 실제 프로젝트 코드에서는 Auto 대신 QR_CODE로 지정했습니다)
망치 [mangchy]   2016-09-02 16:18 X
요즘 파이어몽키 테스트해보다가 예제가 있어 다운로드 하고 apk먼저 설치해서 해보니 바코드가 인식이 잘 되더군요.
그래서 예제 소스랑 github에 있는 라이브러리 다운받고 앞서 강좌에서 수정해야될 부분 2군데 수정하고 컴파일하니 잘되더군요.
그런데 직접 컴파일한 안드로이드 앱은 QR코드는 인식이 잘 되던데 EAN/UPC같은 바코드는 인식이 안되네요....
어떤 이유가 있을까요???

+ -

관련 글 리스트
23 ZXing.Delphi 바코드 스캔 예제 소스 박지훈.임프 3838 2016-06-20
(링크)     C++Builder Tip'N Tricks > ZXing.Delphi 바코드 스캔 예제 소스
(링크)     Delphi Tip'N Tricks > ZXing.Delphi 바코드 스캔 예제 소스
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.