코딩 연습장/Javascript

자바스크립트를 이용한 개인 프로젝트 - 12(영상 처리 알고리즘)

Do아 2021. 6. 16. 10:56
728x90

2021/04/01(목)

 

 

 

 

히스토그램 스트레칭/히스토그램 엔드인/히스토그램 평활화 알고리즘 참고

https://cordingdoah.tistory.com/94

 

자바스크립트를 이용한 개인 프로젝트 - 11(영상 처리 알고리즘)

2021/04/01(목) 유사연산자/라플라시안 알고리즘 참고 https://cordingdoah.tistory.com/93 자바스크립트를 이용한 개인 프로젝트 - 10(영상 처리 알고리즘) 2021/04/01(목) 샤프닝/가우시안/고주파샤프닝 알고리.

cordingdoah.tistory.com

 

 

 

 

이번 게시물에서는 컬러사진 영상처리를 해보겠다

컬러 영상처리 알고리즘 : 흑백처리, 부분흑백처리, 부분 색반전 구현하겠다

 

 

 

 

 

컬러영상처리 원리

- 기존에 흑백 사진 원리와 마찬가지로 디스크에 있는 이미지를 불러와 배열에 저장하고 영상처리를 하여 화면에 내보내는데 차이점은 컴퓨터에서 보여지는 Red, Green, Blue로 이루어진 3차원 배열이 필요하다

 

 

 

 

 

컬러사진 화면에 띄우기

        function openImage() {

            
            init();
            inFile = document.getElementById('selectFile').files[0];
            // 그림파일 --> 이미지 객체
            var inImage = new Image(); // 빈 이미지 객체 생성
            inImage.src = inFile.name;

            inImage.onload = function () {
                // 입력 파일의 크기를 알아냄 (중요!)
                inWidth = inImage.width;
                inHeight = inImage.height;
                // 캔버스 크기를 결정
                inCanvas.width = inWidth;
                inCanvas.height = inHeight;
                inCtx.drawImage(inImage, 0, 0, inWidth, inHeight);
                // 입력 3차원 배열을 준비
                inImageArray = new Array(3); // 3장짜리 배열 (R, G, B)
                for (var i = 0; i < 3; i++) {
                    inImageArray[i] = new Array(inHeight);
                    for (var k = 0; k < inHeight; k++)
                        inImageArray[i][k] = new Array(inWidth);
                }
                // 출력된 캔버스에서 픽셀값 뽑기
                var imageData = inCtx.getImageData(0, 0, inWidth, inHeight);
                var R, G, B, Alpha;
                for (var i = 0; i < inHeight; i++) {
                    for (var k = 0; k < inWidth; k++) {
                        px = (i * inWidth + k) * 4; // 1픽셀 = 4byte
                        R = imageData.data[px + 0];
                        G = imageData.data[px + 1];
                        B = imageData.data[px + 2];
                        // Alpha = imageData.data[px + 3];
                        inImageArray[0][i][k] = String.fromCharCode(R);
                        inImageArray[1][i][k] = String.fromCharCode(G);
                        inImageArray[2][i][k] = String.fromCharCode(B);

                    }
                }
                equalImage();
            }

        }

기존의 raw파일을 띄웠던 것과 비슷하지만 차이점은 R,G,B 변수를 따로 설정하여 3차원 배열에 저장하여 출력

 

 

 

 

<원본이미지 출력배열에 저장 메소드>

        function equalImage() {
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 3차원 배열을 준비
            outImageArray = new Array(3); // 512짜리 1차원 배열
            for (var i = 0; i < 3; i++) {
                outImageArray[i] = new Array(outHeight); // 512짜리 1차원 배열
                for (var k = 0; k < outHeight; k++)
                    outImageArray[i][k] = new Array(outWidth);
            }

            // ***** 진짜 영상처리 알고리즘 *****
            for (var rgb = 0; rgb < 3; rgb++) {
                for (var i = 0; i < inHeight; i++) {
                    for (var k = 0; k < inWidth; k++) {
                        outImageArray[rgb][i][k] = inImageArray[rgb][i][k];
                    }
                }
            }
            displayImage();
        }

 

 

 

 

<컬러이미지 화면에 출력 메소드>

        function displayImage() {
            // 캔버스 크기를 결정
            inCanvas.height = outHeight;
            inCanvas.width = outWidth;

            var R, G, B;
            inPaper = inCtx.createImageData(outWidth, outHeight);
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    R = outImageArray[0][i][k].charCodeAt(0); // Byte 문자를 숫자로.
                    G = outImageArray[1][i][k].charCodeAt(0); // Byte 문자를 숫자로.
                    B = outImageArray[2][i][k].charCodeAt(0); // Byte 문자를 숫자로.
                    inPaper.data[(i * outWidth + k) * 4 + 0] = R;
                    inPaper.data[(i * outWidth + k) * 4 + 1] = G;
                    inPaper.data[(i * outWidth + k) * 4 + 2] = B;
                    inPaper.data[(i * outWidth + k) * 4 + 3] = 255;

                }
            }
            inCtx.putImageData(inPaper, 0, 0);
        }

 

 

 

--> 컬러영상 결과화면

 

 

 

 

<흑백처리>

        //그레이 스케일
        function grayScale() {
            // ***** 진짜 영상처리 알고리즘 *****
            var R, G, B;
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    R = outImageArray[0][i][k].charCodeAt(0);
                    G = outImageArray[1][i][k].charCodeAt(0);
                    B = outImageArray[2][i][k].charCodeAt(0);

                    var RGB = parseInt((R + G + B) / 3);

                    outImageArray[0][i][k] = String.fromCharCode(RGB);
                    outImageArray[1][i][k] = String.fromCharCode(RGB);
                    outImageArray[2][i][k] = String.fromCharCode(RGB);

                }
            }
            displayImage();
            clickEvent();
        }

각각의 RGB 값을 더해 평균값을 구해서 모두 같은 값으로 넣어주면 된다

 

 

 

 

--> 흑백처리 결과화면

 

 

 

 

<부분 흑백처리>

부분 흑백처리는 마우스로 클릭하고 드래그하고 떼면 그 부분만 흑백처리 해주는 처리를 구현했는데 

마우스 이벤트가 필요하다 

 

        //부분 흑백
        var xx, xy, ex, ey;
        function bwImage_Mouse() {

            clickEventDown();

            inCanvas.addEventListener("mousedown", downMouse, false);
            inCanvas.addEventListener("mouseup", upMouse, false);
            function downMouse(e) {
                xx = e.offsetX;
                xy = e.offsetY;
            }

            function upMouse(e) {
                ex = e.offsetX;
                ey = e.offsetY;

                if (xx > ex) {
                    var tmp = xx;
                    xx = ex;
                    ex = tmp;
                }
                if (xy > ey) {
                    var tmp = xy;
                    xy = ey;
                    ey = tmp;
                }

                //네모칸 그리기
                inCtx.beginPath();
                inCtx.strokeStyle = 'Green';   //붓색깔
                inCtx.rect(xx, xy, (ex - xx), (ey - xy));
                inCtx.stroke();
                inCtx.closePath();
                inCanvas.removeEventListener("mousedown", downMouse, false);
                inCanvas.removeEventListener("mouseup", upMouse, false);
                __bwImage_Mouse();

                clickEvent();
            }
        }

1. 클릭하면 mouseDown함수를 수행 ( 현재 좌표 xx,xy 변수에 저장) 하고

2. 드래그 후 마우스를떼면 mouseUp함수를 수행 ( 현재 좌표 ex,ey 변수에 저장)

3. 만약 마우스를 뗐을 때 좌표가 처음 시작 좌표보다 작으면 두 값을 서로 바꿔주기

4. 네모칸을 그리고 이벤트를 없애 준 후 __bwImage_Mouse()함 수 호출

 

 

 

        //부분적 흑백처리
        function __bwImage_Mouse() {

            // ***** 진짜 영상처리 알고리즘 *****
            var R, G, B;
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {

                    if ((xx <= k && ex >= k) && (xy <= i && ey >= i)) {
                        R = outImageArray[0][i][k].charCodeAt(0);
                        G = outImageArray[1][i][k].charCodeAt(0);
                        B = outImageArray[2][i][k].charCodeAt(0);
                        var RGB = parseInt((R + G + B) / 3);

                        if (RGB > 127)
                            RGB = 255;
                        else
                            RGB = 0;
                        outImageArray[0][i][k] = String.fromCharCode(RGB);
                        outImageArray[1][i][k] = String.fromCharCode(RGB);
                        outImageArray[2][i][k] = String.fromCharCode(RGB);
                    }
                    else {
                        outImageArray[0][i][k] = outImageArray[0][i][k];
                        outImageArray[1][i][k] = outImageArray[1][i][k];
                        outImageArray[2][i][k] = outImageArray[2][i][k];
                    }
                }
            }
            displayImage();
        }

좌표의 범위에 해당하는 배열들만 흑백처리를 하고 아니라면 그냥 출력

** 부분 흑백 처리 같은 경우 0과 255로만 표현해서 완전한 흑백처리로 구현했다

그렇기 때문에 일반적인 흑백 처리와 다르게 if문을 이용해서 127보다 크면 255로 127보다 작으면 0으로 치환했다

 

 

 

 

 

--> 부분 흑백처리 결과화면

 

 

 

 

<부분 색반전>

        //색반전
        function reversal() {

            clickEventDown();

            inCanvas.addEventListener("mousedown", downMouse, false);
            inCanvas.addEventListener("mouseup", upMouse, false);
            function downMouse(e) {
                xx = e.offsetX;
                xy = e.offsetY;
            }

            function upMouse(e) {
                ex = e.offsetX;
                ey = e.offsetY;

                if (xx > ex) {
                    var tmp = xx;
                    xx = ex;
                    ex = tmp;
                }
                if (xy > ey) {
                    var tmp = xy;
                    xy = ey;
                    ey = tmp;
                }
                //네모칸 그리기
                inCtx.beginPath();
                inCtx.strokeStyle = 'Green';   //붓색깔
                inCtx.rect(xx, xy, (ex - xx), (ey - xy));
                inCtx.stroke();
                inCtx.closePath();

                inCanvas.removeEventListener("mousedown", downMouse, false);
                inCanvas.removeEventListener("mouseup", upMouse, false);
                __reversal_Mouse();

                clickEvent();
            }
        }

색반전도 부분 흑백처리와 마찬가지로 처리

 

 

        //색반전
        function __reversal_Mouse() {

            // ***** 진짜 영상처리 알고리즘 *****
            var R, G, B;
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {

                    if ((xx <= k && ex >= k) && (xy <= i && ey >= i)) {
                        R = 255 - outImageArray[0][i][k].charCodeAt(0);
                        G = 255 - outImageArray[1][i][k].charCodeAt(0);
                        B = 255 - outImageArray[2][i][k].charCodeAt(0);
                        var RGB = parseInt((R + G + B) / 3);

                        outImageArray[0][i][k] = String.fromCharCode(RGB);
                        outImageArray[1][i][k] = String.fromCharCode(RGB);
                        outImageArray[2][i][k] = String.fromCharCode(RGB);
                    }
                    else {
                        outImageArray[0][i][k] = outImageArray[0][i][k];
                        outImageArray[1][i][k] = outImageArray[1][i][k];
                        outImageArray[2][i][k] = outImageArray[2][i][k];
                    }
                }
            }
            displayImage();
        }

흑백처리와 동일하게 좌표 사이에 있는 값만 색반전 처리, 범위에 있는 값이 아니라면 그냥 출력

 

 

 

 

--> 색반전 결과화면

 

728x90