전기전자/C# 시각화프로그래밍
[C#] 9. 영상처리 프로그램 (WinForm, SubForm 이용하기)
쑨야미
2021. 4. 16. 18:08
WinForm 추가하는 법
WinForm 창 이름 설 (속성)
WinForm Icon 추가 및 변경
SubForm 추가하여 입력값 불러오기
1) 각 창들마다 이름 설정하여서 코딩시 변수로 사용한다. 각 창들 오른쪽 속성누르면 [디자인 - Name] 에서 값변경할 수있다.
2) 버튼 클릭시 동작에 대한 설정이다. 확인 버튼 클릭하면 어떻게 될지에 대한 코드를 아래에 나와있다. (더블 클릭시 코드 변경 란 있음)
3) 입력값을 이용할 떄 NubericUpDown이용하면 된다.
이때 주의할점은 접근시 Private에서 Public으로 해줘야 써먹을수 있다는점 (중요하다.)
이부분은 메인 WinForm 코드란에서 입력값을 불러올 때 사용하는 코드다. 변수 지정하고, 매소드에서 값불러오면 됨.
아래는 영상처리 전체 코드이다.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO; // IOI
namespace Day04_01_영상처리_Beta3
{
public partial class Form1 : Form
{
// 전역 변수
bool flag;
byte[,] inImage, outImage;
double[,] intempImage, outtempImage;
int inH = 0, inW = 0, outH = 0, outW = 0;
String fileName;
Bitmap bitmap;
public Form1()
{
InitializeComponent();
}
/// 메뉴관련함수
private void 화소점처리ToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void 열기ToolStripMenuItem_Click(object sender, EventArgs e)
{
openImage();
}
private void 저장ToolStripMenuItem_Click(object sender, EventArgs e)
{
saveImage();
}
private void 흑백이미지ToolStripMenuItem_Click(object sender, EventArgs e)
{
darkImage();
}
private void 반전이미지ToolStripMenuItem_Click(object sender, EventArgs e)
{
reverseImage();
}
private void 동일이미지ToolStripMenuItem_Click(object sender, EventArgs e)
{
equalImage();
}
private void 밝게어둡게ToolStripMenuItem_Click(object sender, EventArgs e)
{
addImage();
}
private void 확대ToolStripMenuItem_Click(object sender, EventArgs e)
{
zoomInImage();
}
private void 축소ToolStripMenuItem_Click(object sender, EventArgs e)
{
zoomOutImage();
}
private void 좌우반전ToolStripMenuItem_Click(object sender, EventArgs e)
{
leftrightMirror();
}
private void 상하반전ToolStripMenuItem_Click(object sender, EventArgs e)
{
updownMirror();
}
private void 명암대비ToolStripMenuItem_Click(object sender, EventArgs e)
{
contrastImage();
}
private void 포스터라이징ToolStripMenuItem_Click(object sender, EventArgs e)
{
posterizingImage();
}
private void 회전ToolStripMenuItem_Click(object sender, EventArgs e)
{
rotateImage();
}
//공통함수
void openImage()
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog();
fileName = ofd.FileName;
// 파일의 크기를 알아내기
long fSize = new FileInfo(fileName).Length;
// 중요! 입력메모리의 크기를 알아냄.
inH = inW = (int)Math.Sqrt((double)fSize);
// 입력 메모리 확보
inImage = new byte[inH, inW];
// 파일 --> 입력 메모리 로딩
BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open));
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
inImage[i, k] = br.ReadByte();
br.Close();
// MessageBox.Show(inImage[100, 100].ToString());
//displayImage();
equalImage();
}
void displayImage()
{
// 비트맵 및 픽처박스 크기 조절
bitmap = new Bitmap(outH, outW);
pictureBox1.Size = new Size(outH, outW);
this.Size = new Size(outH + 20, outW + 90);
Color pen;// 비트맵에 콕콕 찍을 펜.
for (int i = 0; i < outH; i++)
for (int k = 0; k < outW; k++)
{
byte data = outImage[i, k]; // 한점(=색상)
pen = Color.FromArgb(data, data, data); //펜에 잉크 묻힘
bitmap.SetPixel(k, i, pen); // 콕! 점찍기.
}
pictureBox1.Image = bitmap;
toolStripStatusLabel1.Text = "크기:" + outH + "x" + outW;
}
//영상처리함수
void equalImage()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
outImage[i, k] = inImage[i, k];
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void darkImage()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
///
SubForm sub = new SubForm();
if (sub.ShowDialog() == DialogResult.Cancel)
return;
int value = (int)sub.nup_value.Value;
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
int pixel = inImage[i, k];
if (pixel < value)
pixel = 0;
else if (pixel > value)
pixel = 255;
outImage[i, k] = (byte)pixel;
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void reverseImage()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
outImage[i, k] = (byte)(255 - inImage[i, k]);
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void addImage()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
//int value = 100;
SubForm sub = new SubForm();
if(sub.ShowDialog()== DialogResult.Cancel)
return;
int value = (int)sub.nup_value.Value;
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
if ((inImage[i, k] + value) >= 255)
outImage[i, k]= 255;
else if ((inImage[i, k] + value) <= 0)
outImage[i, k] = 0;
else outImage[i, k] = (byte)(inImage[i, k] + value);
//outImage[i, k] = (byte)pixel;
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void zoomOutImage()
{
int scale = 2; //2배 축소
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH/scale;
outW = inW/scale;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
outImage[i/scale, k/scale] = inImage[i, k];
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void zoomInImage()
{
int scale = 2; //2배 축소
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH * scale;
outW = inW * scale;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
for (int i = 0; i < outH; i++)
for (int k = 0; k < outW; k++)
{
outImage[i , k] = inImage[i/scale, k/scale];
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void saveImage()
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.DefaultExt = "raw";
sfd.Filter = "로우 이미지(*.raw) | *.raw";
if (sfd.ShowDialog() == DialogResult.OK)
{
string saveFname = sfd.FileName;
BinaryWriter bw = new BinaryWriter(File.Open(saveFname, FileMode.Create));
for (int i = 0; i < outH; i++)
for (int k = 0; k < outW; k++)
bw.Write(outImage[i, k]);
bw.Close();
// 메시지 박스를 보이면 좋음.
}
}
void leftrightMirror()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
// 진짜 영상처리 알고리즘을 구현
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
outImage[i, k] = inImage[i, inW - k - 1];
}
displayImage();
}
void updownMirror()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
// 진짜 영상처리 알고리즘을 구현
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
outImage[i, k] = inImage[inH - i - 1, k];
}
displayImage();
}
void contrastImage()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
//int value = 100;
SubForm sub = new SubForm();
if (sub.ShowDialog() == DialogResult.Cancel)
return;
int value = (int)sub.nup_value.Value;
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
if(value > 0)
{
if ((inImage[i, k] + value) >= 255)
outImage[i, k] = 255;
else if ((inImage[i, k] - value) <= 0)
outImage[i, k] = 0;
else
{
if ((inImage[i, k] ) >= 127)
outImage[i, k] = (byte)(inImage[i, k] + value);
else if ((inImage[i, k]) < 127)
outImage[i, k] = (byte)(inImage[i, k] - value);
}
}
else
{
if ((inImage[i, k] - value) >= 255)
outImage[i, k] = 255;
else if ((inImage[i, k] + value) <= 0)
outImage[i, k] = 0;
else
{
if ((inImage[i, k]) >= 127)
outImage[i, k] = (byte)(inImage[i, k] + value);
else if ((inImage[i, k]) < 127)
outImage[i, k] = (byte)(inImage[i, k] - value);
}
}
//outImage[i, k] = (byte)pixel;
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void posterizingImage()
{
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
//int value = 100;
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
if ((inImage[i, k]) <= 0)
outImage[i, k] = 0;
else if ((inImage[i, k] >= 0)&&(inImage[i, k] < 32))
outImage[i, k] = 16;
else if ((inImage[i, k] >= 32) && (inImage[i, k] < 64))
outImage[i, k] = 48;
else if ((inImage[i, k] >= 64) && (inImage[i, k] < 96))
outImage[i, k] = 80;
else if ((inImage[i, k] >= 96) && (inImage[i, k] < 128))
outImage[i, k] = 112;
else if ((inImage[i, k] >= 128) && (inImage[i, k] < 160))
outImage[i, k] = 144;
else if ((inImage[i, k] >= 160) && (inImage[i, k] < 192))
outImage[i, k] = 176;
else if ((inImage[i, k] >= 192) && (inImage[i, k] < 224))
outImage[i, k] = 208;
else if ((inImage[i, k] >= 224) && (inImage[i, k] < 255))
outImage[i, k] = 240;
else
outImage[i, k] = 255;
}
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
void rotateImage()
{
int CenterH, CenterW, newH, newW;
double Radian, PI;
//mReHeight = mHeight;
//mReWidth = mWidth;
//mReSize = mReHeight * mReWidth;
// 중요! 출력 이미지의 크기. --> 알고리즘에 의존.
outH = inH;
outW = inW;
// 출력 이미지 메모리 할당
outImage = new byte[outH, outW];
/// 진짜! 영상처리 알고리즘을 구현
SubForm2 sub2 = new SubForm2();
if (sub2.ShowDialog() == DialogResult.Cancel)
return;
int degree = (int)sub2.degValue.Value;
PI = 3.14159265358979;
Radian = (double)degree * PI / 180.0;
CenterH = inH / 2;
CenterW = inW / 2;
intempImage = new double[inH, inW];
outtempImage = new double[outH, outW];
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
intempImage[i, k] = (double)inImage[i,inW+ k];
}
for (int i = 0; i < inH; i++)
for (int k = 0; k < inW; k++)
{
newH = (int)((i-CenterH)*Math.Cos(Radian)
- (k-CenterW)*Math.Sin(Radian) + CenterH);
newW = (int)((i - CenterH) * Math.Sin(Radian)
+ (k - CenterW) * Math.Sin(Radian) + CenterW);
if(newH < 0 || newH >= inH)
{
flag= false;
}
else if(newH <0 || newW >= inW)
{
flag = false;
}
if(flag)
{
outtempImage[i, k] = intempImage[newH,newW];
}
}
for(int i =0; i<outH; i++)
for(int k =0; i<outW; k++)
{
outImage[i, outW + k] = (byte)outtempImage[i, k];
}
//Delete[] intempImage;
//Delete[] outtempImage;
displayImage();
//MessageBox.Show(outImage[100, 100].ToString());
}
}
}