728x90
728x90
C언어 문자열 다루는게 기억이 안나서 막 짰는데 그것 때문에 코드가 많이 지저분해 진 것 같은데,,,
#define _CRT_SECURE_NO_WARNINGS
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include<windows.h>
void DPCMEncoder(double*, int*, int, BITMAPFILEHEADER, BITMAPINFOHEADER);
void write_matrix_to_file(const char* filename, int* matrix, int height, int width);
void makeOutFile(BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo, char* fileName, double* y);
int main() {
BITMAPFILEHEADER bmpFile, bmpFile2;
BITMAPINFOHEADER bmpInfo, bmpInfo2;
FILE* inputFile = NULL, * inputFile2 = NULL;
inputFile = fopen("AICenterY.bmp", "rb"); // 원본 영상
fread(&bmpFile, sizeof(BITMAPFILEHEADER), 1, inputFile);
fread(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, inputFile);
int width = bmpInfo.biWidth, height = bmpInfo.biHeight, size = bmpInfo.biSizeImage, bitCnt = bmpInfo.biBitCount, stride = (((bitCnt / 8) * width) + 3) / 4 * 4, max;
double* y;
y = (double*)calloc(width * height, sizeof(double));
unsigned char* inputImg = NULL;
inputImg = (unsigned char*)calloc(size, sizeof(unsigned char));
fread(inputImg, sizeof(unsigned char), size, inputFile);
// 값 받아오기
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
y[j * width + i] = inputImg[j * stride + 3 * i];
}
}
// 저장 공간, q값 정하기
int* prsy, q = 20;
prsy = (int*)calloc(width * height, sizeof(int));
// 인코딩 시작
DPCMEncoder(y, prsy, q, bmpFile, bmpInfo);
return 0;
}
void DPCMEncoder(double* org, int* prsy, int q, BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo) {
int width = bmpInfo.biWidth, height = bmpInfo.biHeight, size = bmpInfo.biSizeImage;
double* pe, * rs;
pe = (double*)calloc(width * height, sizeof(double));
rs = (double*)calloc(width * height, sizeof(double));
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
// 여긴 시작이라 128을 빼줄 곳
if (i == 0) {
pe[j * width + i] = org[j * width + i] - 128;
// q로 나누기
prsy[j * width + i] = (int)(pe[j * width + i] / q);
// bit 범위 넘어가는 곳은 제한해주기
if (prsy[j * width + i] < -3) prsy[j * width + i] = -4;
else if (prsy[j * width + i] > 2)prsy[j * width + i] = 3;
rs[j * width + i] = 128 + prsy[j * width + i] * q;
}
// 여기는 시작 부분이 아니라 직전 값으로 더한다.
else {
pe[j * width + i] = org[j * width + i] - rs[j * width + i - 1];
// q로 나누기
prsy[j * width + i] = (int)(pe[j * width + i] / q);
//bit 범위 넘어가는 곳은 제한해주기
if (prsy[j * width + i] < -3) prsy[j * width + i] = -4;
else if (prsy[j * width + i] > 2)prsy[j * width + i] = 3;
rs[j * width + i] = rs[j * width + i - 1] + prsy[j * width + i] * q;
}
}
}
// 사진 출력
makeOutFile(bmpFile, bmpInfo, "reconEncY.bmp", rs);
// 양자화 값 출력
write_matrix_to_file("bitstream.txt", prsy, height, width);
free(rs);
free(pe);
}
void write_matrix_to_file(const char* filename, int* matrix, int height, int width) {
FILE* file = fopen(filename, "w");
if (file == NULL) {
perror("파일 열기 실패");
return;
}
// 값에 따라 000 ~ 111 txt 파일에 작성하기
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
if (matrix[j * width + i] == -4) fprintf(file, "%s","000");
if (matrix[j * width + i] == -3) fprintf(file, "%s", "001");
if (matrix[j * width + i] == -2) fprintf(file, "%s", "010");
if (matrix[j * width + i] == -1) fprintf(file, "%s", "011");
if (matrix[j * width + i] == 0) fprintf(file, "%s", "100");
if (matrix[j * width + i] == 1) fprintf(file, "%s", "101");
if (matrix[j * width + i] == 2) fprintf(file, "%s", "110");
if (matrix[j * width + i] == 3) fprintf(file, "%s", "111");
}
}
fclose(file);
}
// 사진 만들어서 내보내기
void makeOutFile(BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo, char* fileName, double* y) {
int width = bmpInfo.biWidth, height = bmpInfo.biHeight, size = bmpInfo.biSizeImage, bitCnt = bmpInfo.biBitCount, stride = (((bitCnt / 8) * width) + 3) / 4 * 4;
unsigned char* outputImg = NULL;
outputImg = (unsigned char*)calloc(size, sizeof(unsigned char));
// Y값 넘기기
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
for (int k = 0; k < 3; k++) outputImg[j * stride + 3 * i + k] = (unsigned char)(y[j * width + i] > 255 ? 255 : (y[j * width + i] < 0 ? 0 : y[j * width + i]));
}
}
// 파일 만드기
FILE* outputFile = fopen(fileName, "wb");
fwrite(&bmpFile, sizeof(BITMAPFILEHEADER), 1, outputFile);
fwrite(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, outputFile);
fwrite(outputImg, sizeof(unsigned char), size, outputFile);
// 변수 제거
fclose(outputFile);
free(outputImg);
}
인코더는 단순합니다. 사진 받아서 이전 값에서 빼주기 -> 양자화(q로 나누기) -> 양자화된 것 보내기
#define _CRT_SECURE_NO_WARNINGS
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include<windows.h>
void DPCMDecoder(int* prsy, int q, BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo);
void read_matrix_from_file(const char* filename, int* matrix, int rows, int cols);
void makeOutFile(BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo, char* fileName, double* y);
int main() {
BITMAPFILEHEADER bmpFile ;
BITMAPINFOHEADER bmpInfo;
FILE* inputFile = NULL;
inputFile = fopen("AICenterY.bmp", "rb"); // 원본 영상
fread(&bmpFile, sizeof(BITMAPFILEHEADER), 1, inputFile);
fread(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, inputFile);
int width = bmpInfo.biWidth, height = bmpInfo.biHeight, size = bmpInfo.biSizeImage, bitCnt = bmpInfo.biBitCount, stride = (((bitCnt / 8) * width) + 3) / 4 * 4, max;
// q = 20, 저장할 공간 만들기
int* prsy, q = 20;
prsy = (int*)calloc(width * height, sizeof(int));
// 디코더 시작
DPCMDecoder(prsy, q, bmpFile, bmpInfo);
free(prsy);
return 0;
}
void DPCMDecoder(int* prsy, int q, BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo) {
int width = bmpInfo.biWidth, height = bmpInfo.biHeight, size = bmpInfo.biSizeImage;
double* rs;
rs = (double*)calloc(width * height, sizeof(double));
// prsy에 값 받아오기
read_matrix_from_file("bitstream.txt", prsy, height, width);
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
if (i == 0) {
// 0위치는 128에서 더하기
rs[j * width + i] = 128 + prsy[j * width + i] * q;
}
else {
// 나머지 위치는 직전 값에서 더하기
rs[j * width + i] = rs[j * width + i - 1] + prsy[j * width + i] * q;
}
}
}
// 파일 만들기
makeOutFile(bmpFile, bmpInfo, "reconDecY.bmp", rs);
free(rs);
}
void read_matrix_from_file(const char* filename, int* matrix, int height, int width) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
perror("파일 열기 실패");
return;
}
int a[3];
// 파일 읽기 시작
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
for (int k = 0; k < 3; k++) {
// 값 한개씩 읽어서 저장하기
a[k]=fgetc(file);
}
if (a[0] == '0') { // 0
if (a[1] == '0') { // 00
if (a[2] == '0') { //000
matrix[j * width + i] = -4;
}
else { //001
matrix[j * width + i] = -3;
}
}
else { // 01
if (a[2] == '0') { //010
matrix[j * width + i] = -2;
}
else { //011
matrix[j * width + i] = -1;
}
}
}
else { //1
if (a[1] == '0') { // 10
if (a[2] == '0') { //100
matrix[j * width + i] = 0;
}
else { //101
matrix[j * width + i] = 1;
}
}
else {// 11
if (a[2] == '0') {//110
matrix[j * width + i] = 2;
}
else { // 111
matrix[j * width + i] = 3;
}
}
}
}
}
fclose(file);
}
// 사진 만들어서 내보내기
void makeOutFile(BITMAPFILEHEADER bmpFile, BITMAPINFOHEADER bmpInfo, char* fileName, double* y) {
int width = bmpInfo.biWidth, height = bmpInfo.biHeight, size = bmpInfo.biSizeImage, bitCnt = bmpInfo.biBitCount, stride = (((bitCnt / 8) * width) + 3) / 4 * 4;
unsigned char* outputImg = NULL;
outputImg = (unsigned char*)calloc(size, sizeof(unsigned char));
// Y값 넘기기
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
for (int k = 0; k < 3; k++) outputImg[j * stride + 3 * i + k] = (unsigned char)(y[j * width + i] > 255 ? 255 : (y[j * width + i] < 0 ? 0 : y[j * width + i]));
}
}
// 파일 만드기
FILE* outputFile = fopen(fileName, "wb");
// 파일 작성
fwrite(&bmpFile, sizeof(BITMAPFILEHEADER), 1, outputFile);
fwrite(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, outputFile);
fwrite(outputImg, sizeof(unsigned char), size, outputFile);
// 변수 제거
fclose(outputFile);
free(outputImg);
}
디코더는 더 단순하네요
양자화된 것 받아서 복구하기
메모장에는 대충 이렇게 되어 있습니다.
101100100100100100101011100100101100100100011100100100100100100101011100100100100001100100011100100100011100100100110010100111010011111001100111100000111101000110110001101111000100111010011111010011111010011111010011111011010111011010111100001111100001111100001111100001111011001111101001110101001110100010111100010100100100100100100100100100100100100110100101100010100100100100100101011100100101100100011100100100100011011100100100011101100101100101100011101101100101100011011101100011100011100100100100111011010101101011100100101011100100100100100100101100011100101100100100100011100100100100110100100100011011101101100100010100100100100100101101100100100100100011011100011100100100101101100011101101100100100100100100100101010110011100110100011100100011100100100100100010110100100100100010110100100100100101100010100011011010101110100101010011100100100100100101100100100110100100100011100100100101011101100100100100100100100100100100100100100100100100011100100100100011100100100100110100100110011011100100101101100100100011100100100100100100100100100101100011011100100101011100100100100010101100100101100100011100010100100101100100100100100011100100101100100100011100100101100100100100100101100101100010110011100100100100011101100011100100100100101100100011101100100100100011100100100100100100100011100110101100100100100100011100100100100100100100100100100100100100100100100101100100100011011100100100101101011011100100100110100100011101100100100100100101010100100011101110100011011100101100100010100110100100101011100011100010100100101100100100100100100100100101100011011100101100100100100100100100100100100011101101100011001100100011100100100011100100100110001110111000100111010011111010011111010011111011001110111000101111000101111000101111000101111000100111001100111001100111010100111001011111010011111010011111010011111011010111001100111011010100101100011100101100100100100100100100100101101100011100100100101100100011011101100100100100100100100010100100100100100100100101101011100100110101100011100011100101100100100011100100100100101011100100100100100100101011100100100100100101100100100100100100100011100100100101100100100100100100011100100101101100010100011100100100101100101110100100100100011010011100100100100110100100100011010101111011100101100101100011011011111011100101100100100100101011011100100100010101101011101011011100100110
한줄로 된 0과 1의 연속입니다.
저기서 3개씩 받아와서 읽습니다.
q가 크다보니 손상이 크네요...
3비트밖에 안해줘서 양자화 범위가 -4 ~ 3밖에 안되는 것도 이 사진에 문제가 되겠네요
둘의 psnr 은 99.99입니다!
728x90
'언어 > C' 카테고리의 다른 글
C언어 영상처리 - DPCM (0) | 2024.05.23 |
---|---|
C언어 영상처리 - 노이즈 제거 및 업셈플링 (0) | 2024.05.21 |
C언어 영상처리 - data 파일에 넣은 사진 psnr 자동 계산하기 (0) | 2024.05.16 |
C언어 영상처리 - 노이즈 제거, 업스케일링 기록용 (1) | 2024.05.16 |
C 언어 영상처리 - Sobel Filter, 윤곽선 검출, Edge Detection (0) | 2024.05.07 |