기하학 처리
영상을 구성하는 화소의 공간적 위치를 재배치하는 과정
ex) 상하 미러링, 좌우 미러링, 축소하기, 확대하기, 이동하기, 회전하기
<상하 미러링>
-상하를 담당하는 열의 값을 최댓값에서 빼면 상하 미러링 처리된다
temp = inImage[i][k]
inImage[i][k] = inImage[inH-i-1][k]
inImage[inH-i-1][k] = temp
function upDownImage() { // 영상 상하미러링 알고리즘
outH = inH;
outW = inW;
// 출력 영상의 2차원 메모리 할당
outImage = new Array(outH);
for(let i=0; i<outH; i++)
outImage[i] = new Array(outW);
// **** 진짜 영상처리 알고리즘 *****
let temp;
for (let i = 0; i < inH/2; i++) {
for (let k = 0; k < inW; k++) {
temp = inImage[i][k];
inImage[i][k] = inImage[inH-i-1][k];
inImage[inH-i-1][k] = temp;
}
}
for (let i = 0; i < inH; i++) {
for (let k = 0; k < inW; k++) {
outImage[i][k] = inImage[i][k];
}
}
// ******************************
displayImage();
}
<좌우 미러링>
-좌우를 담당하는 행의 값을 최댓값에서 빼면 좌우 미러링 처리된다
temp = inImage[i][k]
inImage[i][k] = inImage[i][inW-k-1]
inImage[i][inW-k-1] = temp
function leftRightImage() { // 영상 좌우미러링 알고리즘
outH = inH;
outW = inW;
outImage = new Array(outH);
for(let i=0; i<outH; i++)
outImage[i] = new Array(outW);
// **** 진짜 영상처리 알고리즘 *****
let temp;
for (let i = 0; i < inH; i++) {
for (let k = 0; k < inW / 2; k++) {
temp = inImage[i][k];
inImage[i][k] = inImage[i][inW-k-1];
inImage[i][inW-k-1] = temp;
}
}
for (let i = 0; i < inH; i++) {
for (let k = 0; k < inW; k++) {
outImage[i][k] = inImage[i][k];
}
}
// ******************************
displayImage();
}
<축소하기(÷2)>
-원본 이미지의 행과 열을 축소 배율로 나누어 출력
outImage[parseInt(i/scale)][parseInt(k/scale)]= inImage[i][k])
function zoomOutImage() { // 축소 알고리즘
let scale = parseInt(prompt("배율","2"));
outH = parseInt(inH/scale);
outW = parseInt(inW/scale);
outImage = new Array(outH);
for(let i=0; i<outH; i++)
outImage[i] = new Array(outW);
// **** 진짜 영상처리 알고리즘 *****
for (let i=0; i<inH; i++) {
for (let k=0; k<inW; k++) {
outImage[parseInt(i/scale)][parseInt(k/scale)]= inImage[i][k];
}
}
// ******************************
displayImage();
}
<확대하기(×2)>
-입력 이미지의 화소는 출력 이미지의 행과 열을 입력한 배율만큼 나눈 값으로 지정
-커진 출력 이미지 공간에 이웃 화소를 채워 넣는 방식
outImage[i][k]= inImage[parseInt(i/scale)][parseInt(k/scale)]
function zoomInImage() { // 확대 알고리즘. 백워딩(홀이 안 생기도록)
let scale = parseInt(prompt("배율","2"));
outH = parseInt(inH*scale);
outW = parseInt(inW*scale);
outImage = new Array(outH);
for(let i=0; i<outH; i++)
outImage[i] = new Array(outW);
// **** 진짜 영상처리 알고리즘 *****
for (let i=0; i<outH; i++) {
for (let k=0; k<outW; k++) {
outImage[i][k]= inImage[parseInt(i/scale)][parseInt(k/scale)];
}
}
// ******************************
displayImage();
}
<이동하기(50,50)>
-출력 이미지 값에 입력값을 더하여 이미지를 좌표상에서 이동
if (i+y < outH && k+x < outW)
outImage[i+y][k+x] = inImage[i][k];
else outImage[i][k] === undefined
function moveImage() { // 영상 이동 알고리즘
outH = inH;
outW = inW;
outImage = new Array(outH);
for(let i=0; i<outH; i++)
outImage[i] = new Array(outW);
// **** 진짜 영상처리 알고리즘 *****
let x = parseInt(prompt("x축 이동", "50"));
let y = parseInt(prompt("y축 이동", "50"));
for (let i=0; i<outH; i++) {
for (let k=0; k<outW; k++) {
if (i+y < outH && k+x < outW)
outImage[i+y][k+x] = inImage[i][k];
else outImage[i][k] === undefined;
}
}
// ******************************
displayImage();
}
<회전하기(캔버스 크기 유지)>
-radian으로 변경하여 사용
radian = angle * Math.PI / 180.0
cx = outH / 2
cy = outW / 2
yin = parseInt(Math.cos(radian)*(k-cx) + Math.sin(radian)*(i-cy) + cx )
xin = parseInt(-Math.sin(radian)*(k-cx) + Math.cos(radian)*(i-cy) + cy )
outImage[i][k] = inImage[xin][yin]

function rotate1Image() { // 회전 알고리즘
// (중요!) 출력 이미지의 크기가 결정 ---> 알고리즘에 의존...
outH = inH;
outW = inW;
// 출력 영상의 2차원 메모리 할당
outImage = new Array(outH);
for(let i=0; i<outH; i++)
outImage[i] = new Array(outW);
// 초기화 (255)
for (let i=0; i<outH; i++)
for (let k=0; k<outW; k++)
outImage[i][k] = 255;
// **** 진짜 영상처리 알고리즘 *****
let degree = parseInt(prompt("각도","45"));
let radian = degree * Math.PI / 180.0;
let cx = outH / 2;
let cy = outW / 2;
// xout = cos*xin - sin*yin
// yout = sin*xin + cos*yin
for (let i=0; i<outH; i++) {
for (let k=0; k<outW; k++) {
let yin = parseInt(Math.cos(radian)*(k-cx) + Math.sin(radian)*(i-cy) + cx );
let xin = parseInt(-Math.sin(radian)*(k-cx) + Math.cos(radian)*(i-cy) + cy );
if ((0 <= xin && xin < inH )&& (0 <= yin && yin < inW ))
outImage[i][k] = inImage[xin][yin];
}
}
// ******************************
displayImage();
}
<회전하기(원본 크기 유지)>
-출력 이미지의 회전 후 크기를 미리 확인하여 목적지의 중앙에서 회전 시키는 방식
radian = degree * Math.PI / 180.0
cx = outH / 2
cy = outW / 2
yin = parseInt(Math.sin(radian)*(i-cx) + Math.cos(radian)*(k-cy)+cy/outW*inW)
xin = parseInt(Math.cos(radian)*(i-cx)-Math.sin(radian)*(k-cy)+cx/outH*inH)
outImage[i][k] = inImage[xin][yin]
function rotate2Image() { // 영상 회전 알고리즘
let degree = parseFloat(prompt("각도","45"));
//회전할 각의 크기를 입력받아 degree에 저장한다.
//각도를 라디안으로 변경
let radian = degree*Math.PI/180.0;
outH=parseInt(Math.abs(Math.cos(radian)*inH) + Math.abs(Math.cos(Math.PI/2-radian)*inW));
outW= parseInt(Math.abs(Math.cos(radian)*inW) + Math.abs(Math.cos(Math.PI/2-radian)*inH));
//출력할 배열 생성
outImage=new Array(outH);
for(let i=0;i<outH;i++)
outImage[i]=new Array(outW);
//출력 배열을 0으로 초기화
for(let i=0;i<outH;i++){
for(let k=0;k<outW;k++){
outImage[i][k]=255;
}
}
//xin,yin는 이미지를 이동시킬 목적지 좌표(인덱스)이다.
let xin, yin;
//cx,cy는 이미지의 중심 좌표값이다.
//이미지가 한 부분을 고정으로 돌아감
let cx=parseInt(outH/2);
let cy=parseInt(outW/2);
//목적지 인덱스를 활용해서 출력 이미지에 원본이미지를 대입
for(let i=0;i<outH;i++){
for(let k=0;k<outW;k++){
//이것 역시 삼각함수의 2배각 공식
xin=parseInt(Math.cos(radian)*(i-cx)-Math.sin(radian)*(k-cy)+cx/outH*inH);
yin=parseInt(Math.sin(radian)*(i-cx) + Math.cos(radian)*(k-cy)+cy/outW*inW);
//목적지 인덱스가 원본이미지의 인덱스 내에 있는 수라면
//출력 배열에 대입
if((0<=xin && xin <inH) && (0<=yin && yin <inW))
outImage[i][k]=inImage[xin][yin];
}
}
// ******************************
displayImage();
}