Skip to content

Instantly share code, notes, and snippets.

@takatakamanbou
Last active May 18, 2020 09:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takatakamanbou/312465d5a7c2d8c5f24dbfb38afe7433 to your computer and use it in GitHub Desktop.
Save takatakamanbou/312465d5a7c2d8c5f24dbfb38afe7433 to your computer and use it in GitHub Desktop.
PIP2020-06-note3.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "PIP2020-06-note3.ipynb",
"provenance": [],
"collapsed_sections": [
"rKbdoWPcCpNf"
],
"toc_visible": true,
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/takatakamanbou/312465d5a7c2d8c5f24dbfb38afe7433/pip2020-06-note3.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NI3mY1FGZWgV",
"colab_type": "text"
},
"source": [
"# 2020年度パターン情報処理第6回講義資料その3\n",
"\n",
"この科目のウェブサイトへ https://www-tlab.math.ryukoku.ac.jp/wiki/?PIP/2020\n",
"\n",
"![hoge](https://www-tlab.math.ryukoku.ac.jp/~takataka/course/PIP/PIP-logo-96x96.png)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ffaGVK2o5VWe",
"colab_type": "text"
},
"source": [
"## はじめに"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0IpujRN_Wuib",
"colab_type": "text"
},
"source": [
"### これは何?\n",
"\n",
"これは,Google Colaboratory(以下 Google Colab) という,Google が提供しているサービスを利用して作成した資料です.Notebook と呼びます.クラウド上に仮想的に構築された Linux マシン上で Python のプログラムを実行することができます."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "QRNjWashW4pr",
"colab_type": "text"
},
"source": [
"### Notebook の動かし方\n",
"\n",
"この Notebook では,上の方のセルで作った変数や関数を後のセルで使うことがあります.そのため,上の方のセルを実行せずに下の方を実行すると,エラーになることがあります.上から順に実行していきましょう.\n",
"\n",
"また,メニューの「ランタイム」から,「すべてのセルを実行」したりすることも可能です."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1jfSXIY6VNxP",
"colab_type": "text"
},
"source": [
"## 準備\n",
"\n",
"以下のセルは,プログラムを実行するための準備を行うためのものです.このセルを実行してから,先へ進みましょう."
]
},
{
"cell_type": "code",
"metadata": {
"id": "IFYQk7ONZENz",
"colab_type": "code",
"colab": {}
},
"source": [
"# 科学技術計算のライブラリ NumPy のモジュールを np という名前で使えるようにする\n",
"import numpy as np\n",
"# グラフを描くためのライブラリ matplotlib の pyplot を plt という名前でインポート\n",
"import matplotlib.pyplot as plt\n",
"# コンピュータビジョン・画像処理のライブラリ OpenCV のモジュールをインポート\n",
"import cv2"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "807R4hQI5oH9",
"colab_type": "code",
"colab": {}
},
"source": [
"from IPython.display import display, Image\n",
"\n",
"### 画像表示用の関数\n",
"#\n",
"def displayImage(img):\n",
" \n",
" if type(img) is np.ndarray: # 渡されたのが np.ndarray だった(OpenCVの画像はこの形式)\n",
" rv, buf = cv2.imencode('.png', img) # PNG形式のバイト列に変換\n",
" if rv:\n",
" display(Image(data = buf.tobytes())) # 変換できたらバイト列を渡して表示\n",
" return\n",
" elif type(img) is str: # 渡されたのが文字列だった\n",
" display(Image(filename = img))\n",
" return\n",
" \n",
" print('displayImage: error')"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "82S39H2VB8oX",
"colab_type": "text"
},
"source": [
"## 2次元のDCT"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "39pG5akMPrP8",
"colab_type": "text"
},
"source": [
"### 2次元DCTの基底を作る\n",
"\n",
"以下のセルを順に実行して,2次元DCTに関する実験の準備をしましょう."
]
},
{
"cell_type": "code",
"metadata": {
"id": "w9YIPxtAqXsN",
"colab_type": "code",
"colab": {}
},
"source": [
"# DCT の正規直交基底を作る関数\n",
"#\n",
"def getDCTbasis(N):\n",
" \n",
" basis = np.empty((N, N)) # 空の N x N 行列\n",
" basis[0, :] = 1.0 / np.sqrt(N) # 0行目 = 0番目の基底ベクトル\n",
" for k in range(1, N): # k = 1, 2, ..., N-1\n",
" x = np.arange(1, 2*N, 2) # 奇数列 1, 3, ..., 2N-1\n",
" y = np.pi * x * k / (2*N) # cos の中身\n",
" basis[k, :] = np.cos(y) * np.sqrt(2/N)\n",
" \n",
" return basis"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "Lj7BiA-QB-5H",
"colab_type": "code",
"colab": {}
},
"source": [
"### 2D-DCTの基底を作る関数\n",
"#\n",
"def getDCTbasis2D(D):\n",
" dct1d = getDCTbasis(D)\n",
" dct2d = np.empty((D,D,D,D))\n",
" for i in range(D):\n",
" for j in range(D):\n",
" dct2d[i, j, :, :] = dct1d[i, :, np.newaxis] * dct1d[np.newaxis, j, :]\n",
"\n",
" return dct2d"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "1R4gsGcOFahy",
"colab_type": "code",
"colab": {}
},
"source": [
"### 2D-DCTの基底を画像化する関数\n",
"#\n",
"def getDCTbasis2DImage(dct2d):\n",
"\n",
" gap = 2\n",
" D = dct2d.shape[0]\n",
" imgsize = D * (D + gap) + gap\n",
" img = np.zeros((imgsize, imgsize))\n",
"\n",
" for iy in range(D):\n",
" lty = iy*(D + gap) + gap\n",
" for ix in range(D):\n",
" ltx = ix*(D + gap) + gap\n",
" img[lty:lty+D, ltx:ltx+D] = dct2d[iy, ix, :, :]\n",
"\n",
" absmax = np.max(np.abs(img))\n",
" img = img * 127.5 / absmax + 127.5\n",
" \n",
" return img"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "8LBxlrOIHGT9",
"colab_type": "code",
"colab": {}
},
"source": [
"# 8x8 の2次元DCTの基底を可視化 \n",
"D = 8\n",
"dct2d = getDCTbasis2D(D)\n",
"img = getDCTbasis2DImage(dct2d)\n",
"\n",
"# そのままではサイズが小さいので,縦横に拡大して表示\n",
"img2 = cv2.resize(img, None, fx=4, fy=4, interpolation=cv2.INTER_NEAREST)\n",
"displayImage(img2)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "3aPUOIBWS_mW",
"colab_type": "text"
},
"source": [
"上の画像は,8 x 8 の2次元DCTの基底を可視化したもの. 基底は全部で64個ある.以下では,左上を基準として,(i, j) という表記を使って基底を表すことにする.左上のが (0,0) の基底,右上が (0, 7),右下が (7,7). "
]
},
{
"cell_type": "code",
"metadata": {
"id": "-12jHZtBErBR",
"colab_type": "code",
"colab": {}
},
"source": [
"# 基底 (0, 0)\n",
"print(dct2d[0,0])"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "vqMvTsOvFWYZ",
"colab_type": "code",
"colab": {}
},
"source": [
"# 基底 (0,1) 一番上の行の左から2つ目\n",
"print(dct2d[0,1])"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "6ruaoHpPFX0R",
"colab_type": "code",
"colab": {}
},
"source": [
"vec00 = dct2d[0,0].reshape(-1) # 基底(0,0)をベクトル化\n",
"vec01 = dct2d[0,1].reshape(-1) # 基底(0,1)をベクトル化\n",
"\n",
"print(vec00 @ vec00) # @ はベクトル間の内積,行列間の積の演算子\n",
"print(vec00 @ vec01)\n",
"print(vec01 @ vec01)"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "SuLI2ht4PwZq",
"colab_type": "text"
},
"source": [
"### 画像をDCTしてみよう"
]
},
{
"cell_type": "code",
"metadata": {
"id": "USYL1sBSHQDk",
"colab_type": "code",
"colab": {}
},
"source": [
"# 画像を入手\n",
"!wget -nc https://www-tlab.math.ryukoku.ac.jp/~takataka/course/PIP/uni3.png\n",
"\n",
"# 元画像(カラー)を表示\n",
"displayImage('uni3.png')\n",
"print(\"元画像\")\n",
"print()"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "aRKS5MylP8pu",
"colab_type": "code",
"colab": {}
},
"source": [
"# グレイスケール画像として読み込んで表示\n",
"imgSrc = cv2.imread('uni3.png', cv2.IMREAD_GRAYSCALE) # グレイスケール画像として読み込み\n",
"displayImage(imgSrc)\n",
"print('幅{0[1]},高さ{0[0]}'.format(imgSrc.shape))"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "-36x_09KcITY",
"colab_type": "code",
"cellView": "both",
"colab": {}
},
"source": [
"#@title 基底(ix, iy)に対する展開係数の値を可視化してみる.以下の値をいろいろ変えてみよう. { run: \"auto\" }\n",
"ix = 0#@param {type:\"integer\"}\n",
"iy = 0#@param {type:\"integer\"}\n",
"\n",
"D = 8\n",
"dct2d = getDCTbasis2D(D)\n",
"\n",
"# (ix, iy) は以下を満たさないといけない\n",
"assert 0 <= ix and ix < D and 0 <= iy and iy < D\n",
"\n",
"# 展開係数を計算(このやり方は計算効率が悪いので実用的ではない)\n",
"img = cv2.filter2D(imgSrc, cv2.CV_32F, dct2d[iy, ix])\n",
"img = cv2.resize(img, (imgSrc.shape[1]//D, imgSrc.shape[0]//D), interpolation = cv2.INTER_NEAREST)\n",
"\n",
"# 展開係数の値を見やすくスケーリング\n",
"absmax = np.max(np.abs(img))\n",
"img = img / (2*absmax) + 0.5\n",
"img *= 255\n",
"\n",
"# 縦横8倍に拡大して表示\n",
"displayImage(cv2.resize(img, None, fx=8, fy=8, interpolation=cv2.INTER_NEAREST))\n",
"print('基底({0},{1})に対する展開係数の値'.format(ix, iy))"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "8PJxbSvpjCQS",
"colab_type": "text"
},
"source": [
"上記は,基底(ix, iy)に対する展開係数の値をグレイスケール画像として可視化したもの.灰色が0で,黒い画素は負の値,白い画素は正の値を表す.展開係数は元の画像の8x8ブロック毎に求まるので,そのまま可視化すれば縦横1/8の大きさになるが,上記はそれを元画像と同じ大きさに拡大したものに相当する."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rKbdoWPcCpNf",
"colab_type": "text"
},
"source": [
"#### Q. 講義資料 3/6 の2つの図を再現するにはそれぞれ (ix, iy) をいくつにすればよい?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "vioitRY6oMWZ",
"colab_type": "text"
},
"source": [
"### 画像圧縮もどき(一部の展開係数の値だけ使って画像を再構成)"
]
},
{
"cell_type": "code",
"metadata": {
"id": "eDUvc9EjdV3y",
"colab_type": "code",
"colab": {}
},
"source": [
"### (0,0) から (H-1,H-1) までの基底を使って画像を再構成する関数\n",
"#\n",
"def getReconstruction(imgSrc, dct2d, H):\n",
" \n",
" D = dct2d.shape[0]\n",
" wSrc, hSrc = imgSrc.shape[1], imgSrc.shape[0]\n",
" wDst, hDst = wSrc//D*D, hSrc//D*D\n",
" imgDst = np.zeros((hDst, wDst))\n",
" \n",
" # このやり方は効率悪いので実用的ではない\n",
" for iy in range(0, hSrc, D):\n",
" for ix in range(0, wSrc, D):\n",
" x = imgSrc[iy:iy+D, ix:ix+D].reshape(-1).astype(float)\n",
" for jy in range(H):\n",
" for jx in range(H):\n",
" coeff = x @ dct2d[jy, jx, :, :].reshape(-1)\n",
" imgDst[iy:iy+D, ix:ix+D] += coeff * dct2d[jy, jx, :, :]\n",
" \n",
" return imgDst"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "03J-mhhT2L-n",
"colab_type": "code",
"colab": {}
},
"source": [
"#@title 基底(0, 0)から(H-1, H-1)までを使って画像圧縮もどき {run:\"auto\"}\n",
"H = 1#@param {type:\"integer\"}\n",
"D = 8\n",
"\n",
"# H は以下を満たさないといけない\n",
"assert 1 <= H and H <= D\n",
"\n",
"dct2d = getDCTbasis2D(D)\n",
"imgSrc = cv2.imread('uni3.png', cv2.IMREAD_GRAYSCALE)\n",
"imgDst = getReconstruction(imgSrc, dct2d, H)\n",
"\n",
"# 得られた画像を表示\n",
"displayImage(imgDst)\n",
"print('H = {0}'.format(H))"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "QFLVDwwyFVbd",
"colab_type": "text"
},
"source": [
"#### Q. H を変えると画像はどのように変化する?"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "QB9XngD-8c0x",
"colab_type": "text"
},
"source": [
"#### Q (これはおまけ課題です) 自分の好きな画像で実験してみよう. "
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "b1lXyv21DaII",
"colab_type": "text"
},
"source": [
"以下のセルのコメントをもとに画像をアップロードして,上のセルの9行目の 'uni3.png' をそのファイル名に変更して実行すれば....やったひとは,使った画像と圧縮結果の画像(↑の画像を右クリックして保存できます),考察を takataka に Teams チャットで送ってください."
]
},
{
"cell_type": "code",
"metadata": {
"id": "s-sr13ak3ZaM",
"colab_type": "code",
"colab": {}
},
"source": [
"# ファイルをアップロード.このセルを実行して「ファイル選択」ボタンを押して...\n",
"from google.colab import files\n",
"#uploaded = files.upload() # この行の先頭の # を消して実行すると,ファイルをアップロードできる\n",
"!ls -l"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "cRGvvKyh0DRT",
"colab_type": "text"
},
"source": [
"いろいろいじった Notebook を保存したい場合は,メニューで「ファイル」 > 「ドライブにコピーを保存」とすると,自分の Google Drive にコピーを保存することができます."
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment