0
1

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 3 years have passed since last update.

pythonでundo機能を実装してみた。

Last updated at Posted at 2021-09-23

はじめに

undo・・・直前の操作を取り消すこと (パワポのctr+Z)
redo・・・undoで一旦取り消した操作をやり直すこと(パワポのctr+Shift+Z)

画像処理とする際undoとredoがあると便利だなと思い、
自分なりにpythonで実装してみました。

undo redo 実装の説明

undo, redo用のデータを保存するリストをundo_list, redo_listとします。

画像処理をする際に、処理前のデータを都度undo_listに追加することで,後から復元できるようにしていきます。
image.png

undo操作の際は、以下の操作を行います
・現在の画像をredo_listに追加する。
・undo_listの末尾のデータを現在の画像と置き換える。
image.png

redo操作の際はundo操作の逆を行います。
・現在の画像をundo_listに追加する。
・redo_listの画像を、現在の画像と置き換える。
image.png

実際の実装

以上のことを踏まえて、以下のように実装してみました。

class Image(object):
    def __init__(self,data):
        self.data=data
        self.shape=data.shape
        self.undos=[] #undo_list
        self.redos=[] #redo_list

    def __set_undo(self):
        self.undos.append(self.data.copy()) #undo_listの末尾に今のデータを追加    
        if len(self.undos)>5: 
            self.undos.pop(0) #undo listの先頭の値を削除する。
            #undo_listにデータが蓄積されることを防ぐために、
            #5つ以上の数のデータが追加された場合は、リストの先頭のデータを削除。
            
    def __set_redo(self):
        self.redos.append(self.data.copy()) #redo_listの末尾に今のデータを追加 
        if len(self.undos)>5:
            self.redos.pop(0) #redo listの先頭の値を削除する。

    def undo(self):
        if not self.undos: #undo listが空の場合         
            print('ERROR: No undo data')
            sys.exit() 
        self.__set_redo()
        self.data=self.undos.pop(-1) #undo listから一番最後の値を取得し、削除する。

    def redo(self):
        if not self.redos: #redo listが空の場合  
            print('ERROR: No redo data')
            sys.exit() 
        self.__set_undo()
        self.data=self.redos.pop(-1) #redo listから一番最後の値を取得し、削除する。

    #適当な処理
    def add_noise(self,var=30):
        self.__set_undo()
        noise=np.random.normal(scale=var, size=self.shape)
        self.data+=noise
        
    def rot(self, k):
        self.__set_undo()
        self.data=np.rot90(self.data, k=k)
        
    def plot(self):
        plt.figure()
        plt.imshow(self.data,  cmap='gray')


if __name__=='__main__':
    data=misc.ascent().astype(np.float32) # 階段の画像の取得
    img=Image(data)        

適当な処理として、ガウシアンノイズを加える操作と、回転操作の関数を加えました。
各処理の前にself.__set_undo()を行うことで、処理前の画像をundo_listに加えています。

画像処理をしていきます。

    img.plot()     #最初の画像の表示
    img.add_noise()
    img.plot()
    img.rot(k=1)
    img.plot()

image.png

ここからundoしていきます。

    img.undo()
    img.plot()
    img.undo()
    img.plot()

image.png

ここでもう一回img.undo()をするとundo listが空のためエラーが返されます。

ERROR: No undo data
An exception has occurred, use %tb to see the full traceback.

SystemExit

今度はredoしていきます

    img.redo()
    img.plot()
    img.redo()
    img.plot()

image.png

まとめ

自分の勉強がてら、undo機能を作ってみました。
なにかありましたらコメントいただけると幸いです。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?