Canvas라는 elements를 이용해 그림을 그릴 수 있는 기능을 사용할 수 있다. 

해당 캔버스엔 선, 원과 같은 그림을 그리는 기능을 사용할 수 있는데. 

Script 에서 제공하는 이벤트 기능과 합쳐 그림판을 만들 수 있는 것이다.

 

어떻게 동작하는건지 알아보자 

원리는 간단하다!

canvas위 마우스 클릭 이벤트를 감지해서 현재 마우스가 위치한 영역에 좌표를 구하고,

그 좌표에 작은 원을 그려준다. 

마우스가 이동할때 감지되는 mousemove 이벤트는 계속해서 현재 마우스의 위치를 

가져오고 그 위치에 계속해서 원을 그려주는 것이다. 

이렇게 되면 마치 우리가 연필로 그림을 그리듯한 모습을 볼수있다. 

마우스가 움직일때마다 그림을 그려주면 마우스가 움직일때마다 그림을 그리기 떄문에 

아래 코드를 보면 painting 이라는 flag를 추가했다. 

마우스가 클릭되면 이 flag를 true로 변경해 그림을 그리게 시키고.. 

마우스 클릭이 off되면 flag를 false로 변경해서 더이상 그림을 그리지 않도록 처리되는 것이다. 

 

touch 이벤트도 감지하도록 아래 코드에 적어뒀기 때문에 

아이패드, 노트북 펜슬 등으로 터치해도 기능이 잘 동작한다! 

 

아래 샘플코드를 그대로 복사하면

샘플을 확인할 수 있다~ 

 

<canvas id="canvas" ></canvas>
<script src="https://code.jquery.com/jquery-2.1.0.min.js"></script>
<script>
	
	// 캔버스 객체를 가져온다.
	var canvas = document.getElementById("canvas"),
	ctx = canvas.getContext("2d"),
	painting = false, // 그림을 그릴 상황인지 체크하는  flag
	lastX = 0, // 마지막 x 좌표 
	lastY = 0, // 마지막 y 좌표 
	lineThickness = 1; // 펜 굵기 
	
	
	// canvas 사이즈설정	
	canvas.width  = window.innerWidth;
	canvas.height = window.innerHeight;
	
	
	// 터치감지 이벤트  
	 document.body.addEventListener("touchstart", function (e) {
		if (e.target == canvas) {e.preventDefault(); }
		var touch = e.touches[0];
    	var mouseEvent = new MouseEvent("mousedown", {
			clientX: touch.clientX,
			clientY: touch.clientY
		});
		canvas.dispatchEvent(mouseEvent);
				
	}, false);
	
	
	document.body.addEventListener("touchend", function (e) {
		if (e.target == canvas) {
			e.preventDefault();
		}
		
		var touch = e.touches[0];
    	var mouseEvent = new MouseEvent("mouseup", {
			clientX: touch.clientX,
			clientY: touch.clientY
		});
		canvas.dispatchEvent(mouseEvent);
		
	}, false);
	document.body.addEventListener("touchmove", function (e) {
		if (e.target == canvas) {
			e.preventDefault();
		}
		
		var touch = e.touches[0];
		var mouseEvent = new MouseEvent("mousemove", {
			clientX: touch.clientX,
			clientY: touch.clientY
		});
		canvas.dispatchEvent(mouseEvent);
		
	}, false);
		
    
	// 마우스 이벤트 	
	canvas.onmousedown = function(e) {
	    painting = true;
	    ctx.fillStyle = "#000";
	    lastX = e.pageX - this.offsetLeft;
	    lastY = e.pageY - this.offsetTop;
	};

	canvas.onmouseup = function(e){
	    painting = false; // 마우스로 그림그리기가 끝나면 플래그를 변경해준다. 
	}

	
	// 그림을 그려주는 function
	canvas.onmousemove = function(e) {
		
	    if (painting) {
	        mouseX = e.pageX - this.offsetLeft;
	        mouseY = e.pageY - this.offsetTop;

	        // find all points between        
	        var x1 = mouseX,
	            x2 = lastX,
	            y1 = mouseY,
	            y2 = lastY;


	        var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
	        if (steep){
	            var x = x1;
	            x1 = y1;
	            y1 = x;

	            var y = y2;
	            y2 = x2;
	            x2 = y;
	        }
	        if (x1 > x2) {
	            var x = x1;
	            x1 = x2;
	            x2 = x;

	            var y = y1;
	            y1 = y2;
	            y2 = y;
	        }

	        var dx = x2 - x1,
	            dy = Math.abs(y2 - y1),
	            error = 0,
	            de = dy / dx,
	            yStep = -1,
	            y = y1;
	        
	        if (y1 < y2) {
	            yStep = 1;
	        }
	       
	        lineThickness = 3 - Math.sqrt((x2 - x1) *(x2-x1) + (y2 - y1) * (y2-y1))/10;
	        if(lineThickness < 1){
	            lineThickness = 1;   
	        }

	        for (var x = x1; x < x2; x++) {
	            if (steep) {
	                ctx.fillRect(y, x, lineThickness , lineThickness );
	            } else {
	                ctx.fillRect(x, y, lineThickness , lineThickness );
	            }
	            
	            error += de;
	            if (error >= 0.5) {
	                y += yStep;
	                error -= 1.0;
	            }
	        }

	        lastX = mouseX;
	        lastY = mouseY;

	    }
	}
    
	
	// 캔버스에 이미지를 그려준다. 
	// 나의 경우 이미지 위에 그림을 그려야해서 사용함. 
	// 생략가능 
    setBackground();
    function setBackground() {
	    var image = new Image();
	    image.onload = function() {
		    ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
	    }
	    image.src = "/resources/images/suit.png";

    }
    

</script>

 

 

결과 

 

 

* 추가적으로  Hammer.js 를 사용하면  모바일 환경에서 발생되는 더 많은 터치기능(확대, swipe, tab)을 처리할 수 있다. 

 

`

MySQL PK를 변경방법

alter table 테이블명 drop primary key;

alter table 테이블명 add primary key(컬럼1, 컬럼2, 컬럼3);

 

앞서 설정은 다 끝났으니

이제 전처리된 이미지를 Ocr 하는것이 더 잘 되는지 실험해본다. 

 

테스트 클래스 생성!! 

import org.opencv.core.Core; 
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;

public class OpenCVTest {
	 private static final int 
     CV_THRESH_OTSU = 8,
     CV_THRESH_BINARY = 0,
     CV_ADAPTIVE_THRESH_MEAN_C = 0;
	 
	static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }
	
	 public static void main(String[] args) {
		 try {
			String path= "경로상생략/img/";
			String target = path + "tttt.jpg";
		    	
	    	// 변환할 이미지를 저장할 객체 
			Mat gray = new Mat();
			Mat resized = new Mat();
			Mat blured = new Mat();
			Mat equalized = new Mat();
			Mat Threshold = new Mat();
			
			// image read 
			Mat img = Imgcodecs.imread(target,Imgcodecs.IMREAD_UNCHANGED);
			
			// GrayScale
			Imgproc.cvtColor(img, gray, Imgproc.COLOR_RGB2GRAY);
	
			// 밝기 조절  
			//gray.convertTo(gray, -1, 1, 150);
	
			// blur 
			Imgproc.GaussianBlur(gray, blured, new Size(0, 0), 1);
				
			// 이진화
			Imgproc.threshold(blured, Threshold, 0, 255,  CV_THRESH_OTSU + CV_THRESH_BINARY);
				
			Imgproc.adaptiveThreshold(Threshold, Threshold, 255, CV_ADAPTIVE_THRESH_MEAN_C ,CV_THRESH_BINARY, 99, 4);
	
			// Resize
			Size sizeLenna = new Size(img.width()*2, img.height()*2);
			Imgproc.resize(Threshold, resized, sizeLenna);
				
	
			// Equalized 
			Imgproc.equalizeHist(resized, equalized);
			
            // 변환된 이미지를 저장한다.
			Imgcodecs.imwrite(path+"/res.jpg", resized);
			
			// 변환된 이미지를 보여준다.
			HighGui.imshow("res", resized);
			HighGui.waitKey();
			
			// tesseract 적용
			File image = new File(path+"res.jpg");
			Tesseract tesseract = new Tesseract();
	    		tesseract.setDatapath("경로상 생략/tessdata");
			    tesseract.setLanguage("eng");
                      tesseract.setOcrEngineMode(1);
					
			String result = tesseract.doOCR(image);
			System.out.println(result);
			
			
		} catch (TesseractException e) {
			e.printStackTrace();
		}
		
			

			 
    }

}

 

설명) 

openCV에서 제공되는 여러가지 이미지 편집 기능이 있다. 

검색해보니 대부분 OCR 이전 전처리로 진행하는 순서들이 있었는데 

먼저 graySacle를 한 뒤 blur 처리 > 이진화 > 평탄화 작업을 하는거 같아 

그대로 진행해보았고, 내가 필요한건 스캔된 문서이미지를 읽어보는건데 

스캔했을때 특유의 스프레이같은 것들이 있어서 밝기 조절로 좀 지워보려고 추가해 보았다.

 

작업물을 보자. 

전)

결과 

 

 

OpenCV로 전처리한 후 

 

결과)

 

 

 

느낀점 ) 

검색해봤던 여러가지 방식을 테스트 해보았다. 

알려진 방법대로 이미지를 전처리한 뒤 확인해보니

이게 더 잘 보인다고? 하는 생각이 드는 경우가 있었다..

생각해보니 사람이 보는 이미지와 컴퓨터가 읽기 좋은 이미지는 다를테니  

어떻게 해주면 더 잘 읽어줄지 좀 더 고민을 해봐야할거 같다. 

 

결론) 

손글씨를 읽기는 역부족이다.  꼭 필요하다면 상용화된 서비스를 유료로 사용해야겠다..

( 구글에서 제공하는 유료 서비스는 잘 읽었음.. ) 

yolo 프레임웍이라는게 있다는데,, 직접 OCR을 만들어보고 싶다. 

'OCR' 카테고리의 다른 글

Java + OpenCV 사용법  (0) 2022.04.08
[Maven] Tesseract 사용법  (0) 2022.04.08
OCR 알아보기 시작!!  (0) 2022.04.07

 

OpenCV 작업환경 구성! 

1. 라이브러리 다운 

아래 사이트에 접속해서 라이브러리 다운로드가 필요하다. 

https://opencv.org/releases/

 

Releases - OpenCV

Become a Member Stay up to date on OpenCV and Computer Vision news Join our Newsletter  

opencv.org

 

사이트 접속하면 메인화면에 나오는 부분에서 Window를 클릭해준다. 

페이지가 이동되면서 파일은 자동으로 다운로드 된다, 

 

다운로드 받은 파일의 압축을 풀어준다. 

 

압축이 풀린 파일을 들어가보면 java를 위한 jar 파일이 있다. 

 

 

이클립스를 열어서 라이브러리를 추가해준다. 

 

추가한 라이브러리의 location을 설정해주는데 

아까 다운받은 파일의 디렉토리를 보면  아래와 같은 .dll 파일을 찾을 수 있다. 이 경로로 설정해준다. 

 

스탬프 순서대로 진행해주면 된다.  

 

 

테스트를 진행할 Class 를 만든다. 

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

public class OpenCVTest{

	public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        System.out.println(Core.NATIVE_LIBRARY_NAME);
        Mat mat = Mat.eye(5, 5, CvType.CV_8UC(1));
        System.out.println(mat.dump());

    }
}

 

결과코드로 아래와 같이 나오면 준비 완료! 

'OCR' 카테고리의 다른 글

[JAVA] OpenCV + Tesseract 사용법  (0) 2022.04.08
[Maven] Tesseract 사용법  (0) 2022.04.08
OCR 알아보기 시작!!  (0) 2022.04.07

1. 먼저 Tesseract 라이브러리를 불러온다

maven 사이트 접속해서 오늘날짜 기준 가장 최신버전으로 선택했다. 

https://mvnrepository.com/artifact/net.sourceforge.tess4j/tess4j/5.2.0

 

2. pom.xml에 dependency 추가. 

<dependency>
	<groupId>net.sourceforge.tess4j</groupId>
	<artifactId>tess4j</artifactId>
	<version>4.5.2</version>
</dependency>

 

3. 테스트를 위한 Class 생성 ! 

import java.io.File;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;


public class OcrTest {
		
	 public static void main(String[] args) {
		 try {
		    // 읽어볼 이미지를 가져온다. 
		    File image = new File("경로상생략/res.jpg");

                    Tesseract tesseract = new Tesseract();
                    tesseract.setDatapath("경로상생략/tessdata"); //** 학습된데이터가 있는 폴더를 지정해준다. 
                    tesseract.setLanguage("eng"); // 언어설정 
                    tesseract.setPageSegMode(1); // 페이지 모드 설정
                    tesseract.setOcrEngineMode(1); 
                    // tesseract.setHocr(true); // html로 그려주는 flag
                    String result = tesseract.doOCR(image);
                    System.out.println(result);

		 
		 } catch (TesseractException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		 }
		 
		 
	 }

}

  

 tesseract.setDatapath("경로상생략/tessdata");  이 라인은 tesseract가 이미지를 읽었을때 

비교할 학습된 데이터 파일의 경로를 가르킨다. 

아래 링크에 접속해보면 이미 학습된 데이터를 제공하고 있으므로 내가 하고자 하는 언어를 다운받아서 넣어두면 된다. 

https://github.com/tesseract-ocr/tessdata

 

GitHub - tesseract-ocr/tessdata: Trained models with support for legacy and LSTM OCR engine

Trained models with support for legacy and LSTM OCR engine - GitHub - tesseract-ocr/tessdata: Trained models with support for legacy and LSTM OCR engine

github.com

 

접속해보면 아래와 같은 파일들이 나오는데 앞 글자가 언어를 가르키고 있다. 

 

나는 영문과 중문이 필요하므로 아래 이미지와 같이 구성하였다. 

 

 

테스트로 사용한 이미지 

 

결과 ) 

 

 

결론)

위에 올린 이미지 말고도 여러개의 이미지를 테스트 해보았으나 

연습용 정도의 퀄리티만 나올 뿐, 업무에 적용해보긴 어려울거 같다는 판단이 든다. 

 

어떻게 하면 인식률을 올릴 수 있을까? 

 OpenCV 라이브러리를 이용해 이미지 흑백으로 바꾸고 블러등등.. 을 이용해

이미지를 더 깔끔하게 만들어 준다면  인식하는데 효과가 있다고한다.

OpenCV 적용을 해보도록한다. 

 

* 손글씨는 50% 정도만 인식되는걸로 보임. 

 

'OCR' 카테고리의 다른 글

[JAVA] OpenCV + Tesseract 사용법  (0) 2022.04.08
Java + OpenCV 사용법  (0) 2022.04.08
OCR 알아보기 시작!!  (0) 2022.04.07

+ Recent posts