포시코딩

디아블로4 경매 사이트 만들기 (4) - Vue에서 Drag&Drop, Crop, Tesseract 사용하기 본문

개인프로젝트/OCR

디아블로4 경매 사이트 만들기 (4) - Vue에서 Drag&Drop, Crop, Tesseract 사용하기

포시 2023. 6. 21. 19:07
728x90

개요

지금까지 React를 사용했지만 더 다양한 언어를 경험하고자 Vue를 사용하기로 결정했다.

마침 비교적 최근에 Vue 3.0 업데이트가 있어서 기존과 다른 부분이 생겼는데 아래 링크를 통해 확인 가능하다.

 

https://4sii.tistory.com/606

 

[Vue 3.0] data()와 methods() 대신 setup() 사용하기

개요 오랜만에 Vue를 통해 프론트엔드를 구현하게 되었는데 Vue 2.0때와 사용 방법이 크게 달라지는 부분이 있어 포스팅하게 되었다. Before export default { data() { return { inputRef: null, uploadedImage: '', }; }

4sii.tistory.com

 

이제 세 번에 걸쳐 진행한 이미지를 드래그 앤 드랍으로 올려 crop한 결과물에 대해 텍스트 인식하는 코드를 알아보자

 

설치

npm i vue-cropperjs tesseract.js
<script>
import { ref } from 'vue';
import VueCropper from 'vue-cropperjs';
import 'cropperjs/dist/cropper.css';
import Tesseract from 'tesseract.js';

export default {
  components: {
    VueCropper,
  },
  setup() {
    // 여기서 javascript 코드 진행
  }
}
</script>

 

기능구현

Drag & Drop

<div class="input-div" @drop="handleDrop">
  <p>여기로 이미지를 드래그하거나 <strong>클릭</strong>하세요.</p>
  <input ref="inputRef" type="file" class="file" @change="handleChange" accept="image/*"/>
</div>
const inputRef = ref(null);
const uploadedImage = ref('');
const cropperRef = ref(null);

const handleDrop = (e) => {
  e.preventDefault();
  const file = e.dataTransfer.files[0];
  if (typeof FileReader === 'function') {
    const reader = new FileReader();
    reader.onload = (event) => {
      uploadedImage.value = event.target.result;
      cropperRef.value.cropper.replace(event.target.result);
    };
    reader.readAsDataURL(file);
  } else {
    alert('FileReader API를 지원하지 않습니다.');
  }
};

// handleChange는 생략

drop 이벤트를 통해 input-div 클래스의 div 위에 이미지를 드랍하면 handleDrop이 실행되는 구조이다.

input-div 클래스에 대한 css가 있어야 사용하기 좋으니 참고

이렇게 업로드되는 이미지에 대해 crop 기능을 사용하기 위해 uploadedImage, cropperRef에 위치시켰다.

업로드할 경우 cropper에 의해 위와 같은 결과물을 얻게 되고 이후 Crop 버튼을 통해 원하는 부분만 잘라낼 것이다.

 

Crop

<vue-cropper ref="cropperRef" :src="uploadedImage"/>
<a href="#" role="button" @click.prevent="cropImage">Crop</a>
const cropImage = () => {
  croppedImage.value = cropperRef.value.cropper.getCroppedCanvas().toDataURL();
  recognizeTesseract();
};

Drag&Drop에서 cropperRef, uploadedImage에 업로드 사진 정보를 넣어줬는데

vue-cropper 태그에 의해 위와 같이 파란 영역을 가진 이미지 공간이 나타나게 된다.

 

여기서 Crop 버튼을 눌러 cropImage 함수를 실행시키면 선택한 영역을 잘라 따로 이미지로 만들어

croppedImage에 담기게 하였다.

결과물은 다음과 같다.

 

Tesseract

const recognizeTesseract = () => {
  fetch(croppedImage.value)
  .then(response => response.blob())
  .then(blob => {
    const blobURL = URL.createObjectURL(blob);

    Tesseract.recognize(
      blobURL, 
      'eng+kor', 
      { logger: m => 
        console.log(m) 
      }
    ).catch (err => {
      console.error(err);
    }).then(({ data: { text } }) => { 
      console.log(text); 
    })
  });
}

Tesseract.recognize() 함수 부분은 이전 포스팅과 동일하다. 

다만 이미지 정보를 가져오는 부분이 살짝 다른데

croppedImage를 그대로 사용할 경우 blobURL이 아니라 아니기 때문에 에러가 발생한다.

croppedImage를 출력했을 때 모습
위처럼 blob: ~과 같이 임시 이미지 저장위치가 출력되야 한다.

 

이 부분에 대해 ChatGPT를 통해 아주 쉽게 해결방법을 찾을 수 있었고

RefImpl의 value 부분을 fetch를 통해 위와 같은 과정을 거쳐 blobURL을 얻을 수 있었다.

해당 결과물을 Tesseract.recognize()를 통해 텍스트로 변환하였고 console.log로 뽑아낸 사진은 아래와 같다.

 

 

이 상태에서 줄바꿈과 공백을 없애고 해당 아이템을 특정 키워드를 통해 부위별로 구분지어주는 코드를 작성하면 된다.

const recognizeTesseract = () => {
  fetch(croppedImage.value)
  .then(response => response.blob())
  .then(blob => {
    const blobURL = URL.createObjectURL(blob);

    Tesseract.recognize(
      blobURL, 
      'eng+kor', 
      { logger: m => 
        console.log(m) 
      }
    ).catch (err => {
      console.error(err);
    }).then(({ data: { text } }) => { 
      const target = text.replace(/\s/g, '');
      console.log(target);

      if (target.includes('계정귀속')) {
        alert('계정 귀속된 아이템은 거래할 수 없습니다.');
        return
      }
      if (target.includes('마법') || target.includes('전설')) {
        alert('희귀 아이템만 거래 가능합니다.');
        return
      }
      if (target.includes('목걸이') || target.includes('반지')) {
        document.querySelector('input[name="type"][value="accesesory"]').checked = true;
      } else if (target.includes('투구') || target.includes('가슴방어구') || target.includes('장갑') || target.includes('바지') || target.includes('장화')) {
        document.querySelector('input[name="type"][value="armor"]').checked = true;
      } else {
        document.querySelector('input[name="type"][value="weapon"]').checked = true;
      }

    })
  });
}

이렇게 이미지를 drag&drop으로 올린 후 crop을 통해 특정 부분을 자른 후 

해당 부분의 텍스트를 인식시키는 과정까지 진행해보았다. 

 

만약 여기서 crop을 하지 않고 아이템의 테두리를 학습시켜

자동으로 해당 부분을 잘라내게끔 한다면 사용하기 매우 편해질 것이다. 

728x90