Skip to content

Instantly share code, notes, and snippets.

@spnova12
Created October 31, 2018 05:05
Show Gist options
  • Save spnova12/3c4388f66514e3f7506aa8629453b955 to your computer and use it in GitHub Desktop.
Save spnova12/3c4388f66514e3f7506aa8629453b955 to your computer and use it in GitHub Desktop.
numpy, pytorch에서의 영상 복원 실험 그리고 psnr측정과 자료형
Display the source blob
Display the rendered blob
Raw
{
"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