質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

1269閲覧

python opencvを用いた画像の切り抜き

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/07/17 09:19

編集2019/07/17 09:45

前提・実現したいこと

白地に絵が描いてある画像を与えたときに、絵が描いてある部分だけを切り抜くプログラムを作っています。
白地に絵が描いてるものでどんなものを与えても絵を切り抜けるようにしたいです。

発生している問題・エラーメッセージ

今現在できているものである程度はできるのですがたまに変なところを切り抜く時があります。

該当のソースコード

clip

1import numpy as np 2import cv2 3 4 5#関数定義 6def cannyprocess(img, basename): 7 edges = cv2.Canny(img,100,200) 8 cv2.imwrite("canny\" + basename,edges)#エッジ画像保存 9 can_img = cv2.imread("canny\" + basename)#エッジ画像の読み込み 10 return can_img 11 12def contourprocess(img): 13 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) 14 image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 15 return contours 16 17def maskgenerate(img, basename): 18 back = np.zeros_like(img) 19 cont = contourprocess(cannyprocess(img,basename)) 20 mask = cv2.drawContours(back, cont, -1, color=(255, 255, 255), thickness=-1) 21 cv2.imwrite("mask\" + basename,mask) 22 mask = cv2.imread("mask\" + basename,0) 23 return mask 24 25def mask_and_alpha(base_img, mask_img, basename): 26 bgr_img = cv2.split(base_img) 27 clip = cv2.merge(bgr_img + [mask_img]) 28 cv2.imwrite("clip\" + basename,clip) 29 return clip 30 31#関数定義

main

1# -*- coding: utf-8 -*- 2 3from random import random 4from kivy.app import App 5from kivy.config import Config 6import clip 7import cv2 8import os 9 10# 起動時の解像度の設定 11Config.set('graphics', 'width', '1024') 12Config.set('graphics', 'height', '768') # 16:9 13Config.set('graphics', 'resizable', False) # ウインドウリサイズ禁止 14 15from kivy.uix.widget import Widget 16from kivy.uix.button import Button 17from kivy.graphics import Color, Ellipse, Line 18from kivy.properties import ObjectProperty 19from kivy.uix.behaviors import ToggleButtonBehavior 20from kivy.uix.togglebutton import ToggleButton 21from kivy.utils import get_color_from_hex # 色の16進数表示を可能にする 22from kivy.core.window import Window 23 24class MyPaintWidget(Widget): 25 #pass 26 last_color = '' # 画面クリアを押された場合の最後の色 27 line_width = 3 # 線の太さ 28 29 def on_touch_down(self, touch): 30 if Widget.on_touch_down(self, touch): 31 return 32 33 34 color = (random(), 1, 1) 35 with self.canvas: 36 touch.ud['line'] = Line(points=(touch.x, touch.y), width=self.line_width) 37 38 def set_line_width(self, line_width=3): 39 self.line_width = line_width 40 41 def on_touch_move(self, touch): 42 if touch.ud: # スライダーを動かす際のエラーを解除するため 43 touch.ud['line'].points += [touch.x, touch.y] 44 45 def set_color(self, new_color): 46 self.last_color = new_color 47 self.canvas.add(Color(*new_color)) 48 49class MyCanvasWidget(Widget): 50 51 def clear_canvas(self): 52 MyPaintWidget.clear_canvas(self) 53 54 55class MyPaintApp(App): 56 57 def __init__(self, **kwargs): 58 super(MyPaintApp, self).__init__(**kwargs) 59 self.title = '画像表示' 60 61 def build(self): 62 parent = Widget() 63 self.painter = MyCanvasWidget() 64 65 # 起動時の色の設定を行う 66 self.painter.ids['paint_area'].set_color(get_color_from_hex('#000000')) #黒色を設定 67 return self.painter 68 69 def clear_canvas(self): 70 self.painter.ids['paint_area'].canvas.clear() 71 self.painter.ids['paint_area'].set_color(self.painter.ids['paint_area'].last_color) 72 73 def save_canvas(self): 74 filename_base = 'sample.png' 75 img_path = Window.screenshot("base\" + filename_base) # スクリーンショットを保存する 76 basename = os.path.basename(img_path) 77 img = cv2.imread("base\" + basename) 78 cv2.rectangle(img, (0, 0), (78, 39), (255, 255, 255), thickness=-1) 79 img = img[0:637, 0:1024] 80 clip.mask_and_alpha(img, clip.maskgenerate(img, basename), basename) 81 82class ColorButton(ToggleButton): 83 84 def _do_press(self): 85 if self.state == 'normal': 86 ToggleButtonBehavior._do_press(self)# ボタンを押されてない場合は状態を変更する 87 88 89if __name__ == '__main__': 90 Window.clearcolor = get_color_from_hex('#ffffff') # ウィンドウの色を白色に変更する 91 MyPaintApp().run() 92

mypaint

1#:import hex_color kivy.utils.get_color_from_hex 2 3<ColorButton>: 4 background_normal: 'color_button_normal.png' 5 background_down: 'color_button_down.png' 6 group: 'color' 7 border: (5, 5, 5, 5) 8 on_release: app.painter.ids['paint_area'].set_color(self.background_color) 9 #on_release: app.painter.paint_id.set_color(self.background_color) # こ�?�方法でもset_corlorにアクセス可能 10<MyCanvasWidget>: 11 paint_id:paint_area 12 id: canvas_area 13 14 test:button1 15 Button: 16 text: 'save' 17 color: 1, 1, 1 , 1 18 font_size: 20 19 on_release: app.save_canvas() 20 border: (2, 2, 2, 2) 21 x: 0 22 top: root.top 23 width: 80 24 height: 40 25 26 BoxLayout: 27 orientation: 'vertical' 28 height: root.height 29 30 width: root.width 31 MyPaintWidget: 32 id: paint_area 33 size_hint_y: 0.8 34 35 BoxLayout: 36 orientation: 'horizontal' 37 size_hint_y: 0.1 38 Label: 39 size_hint_x: 0.1 40 text: 'Line width %s' % int(s1.value) if s1.value else 'Line width not set' 41 color: 0,0,0,1 42 Slider: 43 id: s1 44 size_hint_x: 0.9 45 value: 3 46 range: (1,100) 47 step: 1 48 on_touch_down:app.painter.ids['paint_area'].set_line_width(self.value) 49 50 BoxLayout: 51 orientation: 'horizontal' 52 size_hint_y: 0.1 53 clear_btn:button1 54 Button: 55 id: button1 56 text: "Clear" 57 ont_size: 30 58 on_release: app.clear_canvas() 59 60 61 ColorButton: 62 text: "white " 63 color: 0, 0, 0 , 1 64 background_color: hex_color('#ffffff') 65 66 ColorButton: 67 text: "black " 68 state: 'down' 69 background_color: hex_color('#000000') 70 71 ColorButton: 72 text: "red " 73 background_color: hex_color('#ff0000') 74 75 ColorButton: 76 text: "biue " 77 background_color: hex_color('#0000ff') 78 79 ColorButton: 80 text: "green " 81 background_color: hex_color('#008000') 82 83 ColorButton: 84 text: "orange" 85 background_color: hex_color('#ff4500') 86 87 ColorButton: 88 text: "purple" 89 background_color: hex_color('#800080')

clip,mainにはそれぞれ拡張子として.py、mypaintには.kvが付きますイメージ説明
↑失敗例の切り抜き画像

補足情報(FW/ツールのバージョンなど)

python 3.6.8
opencv 3.4.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2019/07/17 09:38

第三者が動作検証できるようにmain処理部分も含めたソースと変になる画像(と変になる例)を添えると回答得られやすいと思います。
guest

回答2

0

ベストアンサー

失敗前の画像もあれば、何をしでかしてしまっているのか伝わりやすくなると思います

サンプルで貼られた失敗画像をみて、思ったのですが
アンチエイリアスかかった絵の場合、背景との中間部分が発生するので
輪郭がキレイにぬけることはまずありえないです。
(閾値などを都度いじることになる)

そうでないなら、こういう抜き方もあります(マスク画像を作るイメージ)

import numpy as np import cv2 def Proc(): img = cv2.imread('./test.bmp') if img is None: return dst = cv2.compare(img , (255,255,255),cv2.CMP_NE ) dst = cv2.bitwise_and(img , dst) cv2.imshow("dst", dst) cv2.waitKey(0) if __name__ == "__main__": Proc()

投稿2019/07/18 12:16

yominet

総合スコア187

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

どんなものを与えても絵を切り抜けるようにしたいです。

白 (B, G, R) = (255, 255, 255) の部分以外が残るように切り抜きたい場合は、numpy を使って以下のようにできます。

python

1import numpy as np 2import cv2 3 4def crop_margin(img): 5 """余白を切り抜く。 6 """ 7 # 白 (255, 255, 255) でないピクセルを取得する。 8 non_white_pixels = np.all(img != (255, 255, 255), axis=2) 9 rows, cols = np.where(non_white_pixels) 10 11 # その範囲で切り抜く。 12 cropped = img[rows.min():rows.max(), cols.min():cols.max()] 13 14 return cropped 15 16 17img = cv2.imread("sample.png") 18 19cropped = crop_margin(img) 20 21cv2.imwrite("cropped.png", cropped)

※ teratail の背景と同化してしまいわかりづらいため、背景が赤として実行した結果です。
上記コードは白を除いて切り抜くようになっています。

イメージ説明

入力画像

イメージ説明

出力画像

投稿2019/07/17 10:35

tiitoi

総合スコア21954

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問