본문 바로가기
프로젝트/한글 게임

7. 이미지 텍스트 인식

by 갱생angel 2024. 4. 14.

1) 클라우드에서 캔버스로 이미지 생성

2) 이미지를 서버로 보냄

3) 서버에서 google vision api로 이미지 텍스트 인식

4) 텍스트를 클라우드로 보냄

 

-백엔드-

 

config - <vision.js> : 이미지 텍스트 인식 기능

const vision = require("@google-cloud/vision");

const CREDENTIALS = {'사용자 계정 비공개 키'};

const CONFIG = {
  credentials: {
    private_key: CREDENTIALS.private_key,
    client_email: CREDENTIALS.client_email,
  },
};

const client = new vision.ImageAnnotatorClient(CONFIG);

const detectText = async (file_path) => { //이미지 텍스트 함수
  try {
    const [result] = await client.textDetection(file_path);
    if (result.fullTextAnnotation.text) {
      return result.fullTextAnnotation.text;
    } else {
      console.error("No text found in the image.");
      return "";
    }
  } catch (error) {
    console.error("Error detecting text:", error);
  }
};

module.exports = detectText;

 

controller - <canvasController.js> : 캔버스 컨트롤러

  -base64 : 이진 데이터를 문자 코드에 영향을 받지 않는 공통 아스키 문자로 표현하기 위해 만들어진 인코딩

    -인코딩 : 문자나 기호들을 컴퓨터가 이용할 수 있는 기호로 암호화

  -Buffer : 이진 데이터들의 스트림을 읽거나, 조작하는 메커니즘.

    -from : 지정된 문자열, 배열 또는 버퍼로 채워진 새 버퍼를 만듬

const asynchHandler = require("express-async-handler");
const fs = require("fs");
const detectText = require("../config/vision");

const postCanvas = asynchHandler(async (req, res) => {
  const { dataURL } = req.body; //클라이언트에서 이미지 데이터를 받음
  const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, "");
  //dataURL에서 base64 인코딩된 이미지 데이터를 추출
  const buffer = Buffer.from(base64Data, "base64"); //추출된 이미지 데이터를 버퍼로 변환

  await new Promise((res, rej) => { //비동기화로 이미지 파일을 생성
    fs.writeFile("image.png", buffer, (err) => {
      if (err) {
        console.error(err);
        rej("이미지 저장 중 에러 발생");
      } else {
        res();
      }
    });
  });

  const text = await detectText("image.png"); //이미지 텍스트 인식 실행
  res.json({ text }); //텍스트 값을 클라이언트로 보냄
});

module.exports = { postCanvas };

 

route - <canvasRoute.js> : 캔버스 라우터

const express = require("express");
const router = express.Router();
const { postCanvas } = require("../controller/canvasController");

router.route("/canvas").post(postCanvas);

module.exports = router;

 

app.js

const express = require("express");
const cors = require("cors");
const dbConnect = require("./config/dbConnect");

const app = express();

dbConnect();

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use("/", require("./route/userRoute"));
app.use("/", require("./route/postRoute"));
app.use("/", require("./route/canvasRoute")); //캔버스 라우터

app.listen(5000, () => {
  console.log("5000 포트에서 서버 실행 중");
});

-프론트엔드-

 

page - Canvas - <Canvas.js>

import React, { useEffect, useRef, useState } from "react";
import axios from "axios";
import "../../css/canvas.css";

function Canvas() {
  const canvasRef = useRef(null);

  const [isDrawing, setIsDrawing] = useState(false); 

  const [lastX, setLastX] = useState(0); 
  const [lastY, setLastY] = useState(0); 

  const [outputImageSrc, setOutputImageSrc] = useState(null); 

  const [path, setPath] = useState([]); 
  const [paths, setPaths] = useState([]); 

  const [imgText, setImgText] = useState(""); //텍스트 값 변수, 함수

  useEffect(() => {
    const canvas = canvasRef.current; 
    const ctx = canvas.getContext("2d"); 

    const drawing = (e) => {
      if (!isDrawing) return; 

      const rect = canvas.getBoundingClientRect();
      const offsetX = e.clientX - rect.left; 
      const offsetY = e.clientY - rect.top; 

      ctx.beginPath(); 
      ctx.moveTo(lastX, lastY); 
      ctx.lineTo(offsetX, offsetY); 
      ctx.strokeStyle = "gray"; 
      ctx.lineWidth = 2; 
      ctx.stroke(); 

      setLastX(offsetX); 
      setLastY(offsetY); 

      setPath((prevPath) => [...prevPath, { x: offsetX, y: offsetY }]); 
    };

    canvas.addEventListener("mousemove", drawing); 

    return () => {
      canvas.removeEventListener("mousemove", drawing);
    };
  }, [isDrawing, lastX, lastY]);


  const drawingCanvas = (e) => {
    setIsDrawing(true);
    const rect = e.target.getBoundingClientRect();
    setLastX(e.clientX - rect.left);
    setLastY(e.clientY - rect.top);
    setPath([{ x: e.clientX - rect.left, y: e.clientY - rect.top }]); 
  };

  const stopDrawing = () => {
    if (isDrawing) {
      setPaths((prevPaths) => [...prevPaths, path]); 
      setPath([]); 
    }
    setIsDrawing(false);
  };

  const canvasOut = () => {
    setIsDrawing(false);
  };

  const outputCanvasImage = async () => {
    const canvas = canvasRef.current;
    setOutputImageSrc(canvas.toDataURL());  //이미지 데이터 URL 화

    const dataURL = canvas.toDataURL("image/png");
    await axios
      .post("http://localhost:5000/canvas", { dataURL: dataURL }) //이미지 URL을 서버로 보냄
      .then((res) => {
        setImgText(res.data.text); //서버에서 받은 텍스트 값을 setImgText에 저장
      });
  };

  const clearCanvas = () => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
    setOutputImageSrc(null); 
    setPaths([]);
    setImgText("");
  };

  const returnCurrentLine = () => {
    setPaths((prevPaths) => prevPaths.slice(0, -1)); 
  };

  const redrawCanvas = () => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext("2d");
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    paths.forEach((p) => {
      ctx.beginPath();
      ctx.moveTo(p[0].x, p[0].y); 
      for (let i = 1; i < p.length; i++) {
        ctx.lineTo(p[i].x, p[i].y);
      }
      ctx.stroke(); 
    });
  };

  useEffect(redrawCanvas, [paths]);

  return (
    <div className="canvas">
      <canvas
        ref={canvasRef}
        width={500}
        height={500}
        style={{ border: "1px solid black" }}
        onMouseDown={drawingCanvas}
        onMouseUp={stopDrawing}
        onMouseOut={canvasOut}
      />
      {outputImageSrc && <img src={outputImageSrc} alt="분석된 이미지" />}
      <div>
        <button onClick={outputCanvasImage}>추출</button>
        <button onClick={clearCanvas}>다시 쓰기</button>
        <button onClick={returnCurrentLine}>한 획 지우기</button>
      </div>
      <div>
        <h1>{imgText}</h1> <!--텍스트 값 나타냄-->
      </div>
    </div>
  );
}

export default Canvas;

 

css - <canvas.css>

.canvas button {
  width: 100px;
  height: 30px;
  font-size: 15px;
  font-weight: bold;
  border: 1px solid black;
  background-color: white;
}

.canvas button:hover {
  color: white;
  background-color: black;
}

'프로젝트 > 한글 게임' 카테고리의 다른 글

9. 이미지, 낱말 데이터 등록  (0) 2024.04.17
8. multer  (0) 2024.04.15
6. Google Vision API  (0) 2024.04.14
5. 선 한 획 씩 삭제하기  (0) 2024.04.11
4. Canvas 다시 쓰기  (0) 2024.04.11