23
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

画像を手早く高画質にする

Last updated at Posted at 2018-10-13

TL;DR

手元にある画像を手っ取り早く高画質にするために、
手軽な方法を調べ、部分的に書き換えて二倍速にした。

はじめに

ちょうどこんな記事を見つけ、頑張れば良い感じの画像が手に入るであろうことは想像が付いていたので
まずは手軽にやる方法を探していました。
そして、見つけたのがRAISRを実装したリポジトリです。
結果の画像を見る限り、割と良い感じだったのでこれを採用して見た訳ですが、
前処理として使うには少々時間がかかり過ぎていたのでmultiprocessingで処理時間を短くしておきました。
RAISRの元論文もあるので、自分でゼロから始める人は、そちらを参考にして下さい。
リポジトリに載っていた結果の画像はこちらです。
WomanOriginWomanRAISR

LineOriginLineRAISR

somethingOriginsomethingRAISR

TigerOriginTigerRAISR

ギザギザしていた部分が、綺麗になっています。

やったこと

test.pyで時間の掛かる処理をしていた部分を並列化しただけです。
元のコードで、何が不味いのかは一目見て分かることでしょう。

for row in range(margin, heightHR-margin):
    for col in range(margin, widthHR-margin):
        if round(operationcount*100/totaloperations) != round((operationcount+1)*100/totaloperations):
            print('\r|', end='')
            print('#' * round((operationcount+1)*100/totaloperations/2), end='')
            print(' ' * (50 - round((operationcount+1)*100/totaloperations/2)), end='')
            print('|  ' + str(round((operationcount+1)*100/totaloperations)) + '%', end='')
            sys.stdout.flush()
        operationcount += 1
        # Get patch
        patch = upscaledLR[row-patchmargin:row+patchmargin+1, col-patchmargin:col+patchmargin+1]
        patch = patch.ravel()
        # Get gradient block
        gradientblock = upscaledLR[row-gradientmargin:row+gradientmargin+1, col-gradientmargin:col+gradientmargin+1]
        # Calculate hashkey
        angle, strength, coherence = hashkey(gradientblock, Qangle, weighting)
        # Get pixel type
        pixeltype = ((row-margin) % R) * R + ((col-margin) % R)
        predictHR[row-margin,col-margin] = patch.dot(h[angle,strength,coherence,pixeltype])
  • 独立に計算しても問題のないものに対してシングルスレッドで処理を実行している
  • pythonでforの二重ループを使っている

ぱっと見ですが、これを書き直すだけで一気に早くなりそうな気がします。
まずは、forの中身を関数化して抜き出します。

argwrapper

という関数はmultiprocessingで関数に引数を複数与えるために使います。

import multiprocessing
def argwrapper(args):
    return args[0](*args[1:])

def calculateValues(numOfRows, upscaledLR, row, col):
    if round(row * 100 / numOfRows) \
            != round((row + 1) * 100 / numOfRows):
        print('|{sharps}{spaces}|  {percent}%'.format(**{
            'sharps': '#' * round((row + 1) *
                                  100 / numOfRows / 2),
            'spaces': ' ' * (50 - round((row + 1) *
                                        100 / numOfRows / 2)),
            'percent': round((row + 1) * 100 / numOfRows)
        }), end='\r')
    # Get patch
    patch = upscaledLR[row - patchmargin: row + patchmargin + 1,
                       col - patchmargin: col + patchmargin + 1]
    patch = patch.ravel()
    # Get gradient block
    gradientblock = upscaledLR[row - gradientmargin: row + gradientmargin + 1,
                               col - gradientmargin: col + gradientmargin + 1]
    # Calculate hashkey
    angle, strength, coherence = hashkey(gradientblock, Qangle, weighting)
    # Get pixel type
    pixeltype = ((row - margin) % R) * R + ((col - margin) % R)
    return {
        "row": row - margin,
        "col": col - margin,
        "value": patch.dot(h[angle, strength, coherence, pixeltype])
    }

そして本題のmultiprocessingの部分です。
先ほど作成した関数の名前を第一引数にし、それ以降に関数の引数を列挙していくだけです。
RAISRの実装だと、行列の更新が必要だったので、最後にまとめて更新を行うことにしました。

poo = multiprocessing.Pool()
funcArgs = [(calculateValues, heightHR - margin,
                upscaledLR, row, col)
            for row in range(margin, heightHR - margin)
            for col in range(margin, widthHR - margin)]
results = poo.map(argwrapper, funcArgs)
poo.close()
poo.join()
for result in results:
    predictHR[result["row"], result["col"]] = result["value"]

multiprocessingを使うとこれだけで並列化ができてしまいます。
簡単ですね。
プログレスバーの部分はあまり気を使っていなかったため、少し雑な感じですが
本質ではないので、無視しています。

結果の確認

とある画像で、実行速度を比較して見ました。
まずは拾ってきたコードでの実行結果です。

  • 315.3537690639496 [s]
  • 309.78351306915283 [s]
  • 360.8852210044861 [s]

次に、multiprocessingで並列化させたコードでの実行結果です。

  • 138.09882402420044 [s]
  • 138.4847867488861 [s]
  • 140.33899188041687 [s]

4coreでやっているとは言え、流石に4倍速にはなりませんでしたが、2~3倍程度には速くなっていそうです。
画像の方も、問題なく綺麗になっていそうです。
スクリーンショット 2018-10-13 20.53.49.png
スクリーンショット 2018-10-13 20.54.08.png

速さにこだわりの持てそうな画像でやって見た場合も以下の様な感じでした。

  • 拾ってきたコード
    • 269.8946466445923 [s]
    • 293.7288279533386 [s]
    • 278.0401508808136 [s]
  • 並列化したコード
    • 139.08394598960876 [s]
    • 133.12141489982605 [s]
    • 138.94682788848877 [s]

まとめ

手軽に2倍速に出来た。
でも、もっと速くなって欲しい。

23
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?