Created
October 31, 2018 05:05
-
-
Save spnova12/3c4388f66514e3f7506aa8629453b955 to your computer and use it in GitHub Desktop.
numpy, pytorch에서의 영상 복원 실험 그리고 psnr측정과 자료형
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# numpy, pytorch에서의 영상 복원 실험 그리고 psnr측정과 자료형 " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### HEVC 비디오 복원 실험을 하는 중, 출력되는 psnr의 값에 약간 오류가 있음을 발견하였다.\n", | |
"#### jupyter notebook 을 사용한 이유는 jupyter notebook은 한줄씩 결과를 출력하여 관찰할 수 있기 때문이다.\n", | |
"#### 아래는 psnr 측정 과정 중의 오류를 찾아가는 과정이다.\n", | |
"\n", | |
"#### 기본적으로 psnr을 측정하기 위해 아래의 함수(get_psnr)를 만들어서 사용하고있다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 417, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def get_psnr(img1, img2, min_value=0, max_value=255):\n", | |
" \"\"\"\n", | |
" psnr 을 계산해준다.\n", | |
" 이미지가 [0., 255] 이면 min_value=0, max_valu=255 로 해주고,\n", | |
" 이미지가 [-1,1]의 범위에 있으면 min_value=-1, max_valu=1 로 설정 해준다.\n", | |
" \"\"\"\n", | |
" if type(img1) == torch.Tensor:\n", | |
" mse = torch.mean((img1 - img2) ** 2)\n", | |
" else:\n", | |
" mse = np.mean((img1 - img2) ** 2)\n", | |
" if mse == 0:\n", | |
" return 100\n", | |
" PIXEL_MAX = max_value - min_value\n", | |
" return 10 * log10((PIXEL_MAX ** 2) / mse)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 이제부터 numpy로 비디오를 읽고 pytorch로 복원하고 psnr 을 뽑는 과정이다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 418, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pydooly import *\n", | |
"from models import *\n", | |
"from os.path import join\n", | |
"import torch\n", | |
"import tqdm\n", | |
"\n", | |
"# 원본 비디오를 불러온다.\n", | |
"video_dir_ori = r'C:\\home\\kdw\\reconNet_1.1\\BQTerrace1\\S11BQTerrace_1920x1080__P420_60Hz_8b_600frm_001.yuv'\n", | |
"# hevc로 손상된 비디오를 불러온다.\n", | |
"video_dir_hevc = r'C:\\home\\kdw\\reconNet_1.1\\BQTerrace1\\S11BQTerrace_1920x1080__P420_60Hz_8b_600frm_QP22_LDB_001.yuv'\n", | |
"# 미리 학습한 모델을 불러온다.\n", | |
"pkl_dir = r'C:\\home\\kdw\\reconNet_1.1\\exp005\\saved_model\\net.pkl'\n", | |
"\n", | |
"# (height, width)\n", | |
"size = (1080, 1920)\n", | |
"\n", | |
"# 비디오를 읽는다.\n", | |
"cap1 = VideoCaptureYUV(video_dir_ori, size)\n", | |
"cap2 = VideoCaptureYUV(video_dir_hevc, size)\n", | |
"ret1, y1, u1, v1 = cap1.read_yuv()\n", | |
"ret2, y2, u2, v2 = cap2.read_yuv()\n", | |
"\n", | |
"y1_backup = np.copy(y1)\n", | |
"y1_backup2 = np.copy(y1)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 419, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"uint8\n" | |
] | |
} | |
], | |
"source": [ | |
"print(y1.dtype)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 비디오의 처음 자료형은 uint8 이므로 딥러닝 연산을 위해 float32 로 바꿔준다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 420, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1 = y1.astype(np.float32)\n", | |
"u1 = u1.astype(np.float32)\n", | |
"v1 = v1.astype(np.float32)\n", | |
"\n", | |
"y2 = y2.astype(np.float32)\n", | |
"u2 = u2.astype(np.float32)\n", | |
"v2 = v2.astype(np.float32)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 이 상태에서 원본과 hevc 사이의 psnr을 측정해보자." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 421, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.7101066507472\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1.astype(np.float32), y2.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 미리 학습되어 저장된 모델을 가져온다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 422, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"===> loading checkpoint 'C:\\home\\kdw\\reconNet_1.1\\exp005\\saved_model\\net.pkl'\n" | |
] | |
} | |
], | |
"source": [ | |
"input_channel = 1\n", | |
"device = torch.device('cuda:0')\n", | |
"netG = Generator_one2many_RDB(input_channel).to(device)\n", | |
"if os.path.isfile(pkl_dir):\n", | |
" print(\"===> loading checkpoint '{}'\".format(pkl_dir))\n", | |
" checkpoint = torch.load(pkl_dir)\n", | |
" epoch = checkpoint['epoch']\n", | |
" best_psnr = checkpoint['best_psnr']\n", | |
" netG.load_state_dict(checkpoint['state_dict_G'])\n", | |
"else:\n", | |
" print(\"===> no checkpoint found at '{}'\".format(pkl_dir))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 모델에 넣기위해 비디오를 알맞은 형태로 transform 해준다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 423, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"transform = Compose([\n", | |
" Color0_255to1_1(),\n", | |
" ToTensor()\n", | |
"])\n", | |
"inverse_transform = Compose([\n", | |
" ToImage(),\n", | |
" Color1_1to0_255(),\n", | |
"])\n", | |
"\n", | |
"# 학습된 모델은 -1 ~ 1 범위로 학습됐으므로, 알맞게 transform을 해준다.\n", | |
"y1 = transform(y1).to(device)\n", | |
"y2 = transform(y2).to(device)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 항상 y1이 원본 y2가 hevc 잊지말기." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 424, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.71010648001696\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1, y2, -1, 1)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### transform 해도 psnr 결과는 처음과 결과가 같다. \n", | |
"#### 모델에 넣기위해서는 텐서의 shape도 변경해 주어야 한다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 425, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1 = y1.view(1, -1, y1.shape[1], y1.shape[2])\n", | |
"y2 = y2.view(1, -1, y2.shape[1], y2.shape[2])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 426, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.71010648001696\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1, y2, -1, 1)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 모델의 shape을 변경해도 결과가 같다. \n", | |
"#### 이제 드디어 hevc 비디오를 모델에 넣어서 복원해보자. \n", | |
"#### 복원된 비디오는 y_new 라고 하자." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 427, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"with torch.no_grad():\n", | |
" netG.eval()\n", | |
" y_new = netG(y2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 428, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.97878728111728\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1, y_new, -1, 1)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 복원된 결과의 psnr이 hevc의 psnr보다 더 개선됨을 확인하였다! \n", | |
"#### inverse_transform 을 한 결과도 확인해보자." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 429, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1 = inverse_transform(y1)\n", | |
"y_new = inverse_transform(y_new)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 430, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.97878575552636\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1, y_new, 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 혹시 y1을 transform하는 과정에서 조금 값이 변하지 않았을까하는 마음에 y1_backup과도 psnr구해봄." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 431, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.97878655159893\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup, y_new, 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 음.. 값이 아주 조금 다르다?" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 432, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"165.5202668218712\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup, y1, 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 역시 값이 아주아주 조금 달라서 psnr 값이 100 이상으로 나왔다." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### inverse_transform 에서도 이상이 없음 확인. \n", | |
"#### tranform 하면서 약간 값이 변하긴 했지만 float32자료형을 사용하기 때문에 어쩔수 없이 생기는 문제라고 판단." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 그런데 비디오의 자료형은 uint 이다. \n", | |
"#### 그래서 자료형을 uint로 형변환 해주자. \n", | |
"#### 당연히 지금 y1의 자료형은 float32이다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 433, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"float32\n" | |
] | |
} | |
], | |
"source": [ | |
"print(y1.dtype)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 434, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1 = y1.astype(np.uint)\n", | |
"y_new = y_new.astype(np.uint)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 435, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"uint32\n" | |
] | |
} | |
], | |
"source": [ | |
"print(y1.dtype)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 436, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.38595623120561\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1.astype(np.float32), y_new.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 헐.. 자료형을 바꿔주면서 psnr이 원본보다 낮아졌다.\n", | |
"#### 이번에는 y1 과 psnr 을 측정하지 않고, 정말 원본인 y1_backup 과 psnr을 측정하였다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 437, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"43.41173344062949\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup.astype(np.float32), y_new.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 방금 전보다는 조금 높지만 여전히 unint 로 형변환 하기 전보다 psnr이 훨씬 낮다. \n", | |
"#### y1과 y1_backup의 차이가 형변환 하면서 꽤 커지나보다??" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 438, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"57.02762511017503\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1.astype(np.float32), y1_backup.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 확인해보니 이렇게 y1과 y1_backup의 값이 살짝 다르다.\n", | |
"## 그래서 이번에는 어느 부분에서 y1 이 변하는지 간단히 실험해보았다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 439, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1_backup2 = np.copy(y1_backup)\n", | |
"y1_backup3 = np.copy(y1_backup)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 먼저 y1_backup을 새로운 변수 y1_backup2와 y1_backup3에 copy해주었다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 440, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"100\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup2.astype(np.float32), y1_backup3.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 당연히 같은 것을 copy했으므로 psnr이 100이 나왔다.\n", | |
"#### 이제 transform을 해주어보았다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 441, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1_backup2 = transform(y1_backup2).to(device)\n", | |
"y1_backup2 = inverse_transform(y1_backup2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 442, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"100\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup2.astype(np.float32), y1_backup.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### transform을 해주어도 psnr이 100이 나왔다.\n", | |
"#### 이번에는 바로 transform을 해주지 않고, uint형을 float32로 바꿔준 후 transform 해줘보았다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 443, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1_backup3 = y1_backup3.astype(np.float32)\n", | |
"y1_backup3 = transform(y1_backup3).to(device)\n", | |
"y1_backup3 = inverse_transform(y1_backup3)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 444, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"165.5202668218712\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup3.astype(np.float32), y1_backup.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 아까 말한것 처럼 uint가 float32형으로 변하면서 두 비디오가 약간 달라지는 듯(float 때문의 오차) \n", | |
"#### 이제는 float32로 변한것을 uint 형으로 바꿔보았다." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 445, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"y1_backup3 = y1_backup3.astype(np.uint)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 446, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"57.02762511017503\n" | |
] | |
} | |
], | |
"source": [ | |
"psnr_y = get_psnr(y1_backup3.astype(np.float32), y1_backup.astype(np.float32), 0, 255)\n", | |
"print(psnr_y)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### 그랬더니 y1_backup2와 y1_backup3의 psnr 이 100이 아니라 57.02762 가 나왔다..." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# 결론...?" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### uint -> float32 -> uint 로 형변환 하는 과정에서 생각보다 큰 오차가 생긴다. \n", | |
"#### 특히 복원된 영상을 uint 로 바꿔주면 psnr이 hevc와 원본과의 psnr보다 더 떨어진다. \n", | |
"#### 모델이 학습될때 원본과 hevc영상의 mse 를 계산할 때, 영상의 자료형을 uint로 해줘야 float32 로 해준 것 보다 최종 비디오의 psnr이 좋게 나오려나?!" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment