@tkr4649 (tk r)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

OpenCV でshapeを使うとエラーになってしまいます

やりたいこと

画像を分割するプログラムを作ろうと思っています。
ひとつ画像の名前を指定して分割するというプログラムは動いたのですが、forをもちいて複数の画像をまとめて分割しようとするとエラーが出てしまいます。
python 3.9.7 visual studio code でやってます、

発生している問題・エラー

AttributeError
'tuple' object has no attribute 'shape'

成功したソースコード

import cv2
import numpy as np
import os
import glob

img = cv2.imread("./hukuzawa.jpg", cv2.IMREAD_COLOR)
print(img)
h,w = img.shape[:2]
print(h)

split_x = 1
split_y = 2

cx = 0
cy = 0

for ix in range(split_x):
    for iy in range(split_y):
        split_pic = img[cy:cy + int(h/split_y), cx:cx + int(w/split_x),:]
        cv2.imwrite("hukuzawa" + "_" + str(iy) + str(iy) + ".jpg", split_pic)
        cy = cy + int(h/split_y)
    cy = 0
    cx = cx + int(w/split_x) 

うまくいかなかったソースコード

import cv2
import numpy as np
import os
import glob

files = glob.glob("./*jpg")
print(files)

split_x = 1
split_y = 2

cx = 0
cy = 0

for f in files:
    print(f)
    img = cv2.imread(f), cv2.IMREAD_COLOR
    print(img)
    h,w = img.shape[:2]
    print(h)
    for ix in range(split_x):
        for iy in range(split_y):
            split_pic = img[cy:cy + int(h/split_y), cx:cx + int(w/split_x),:]
            cv2.imwrite(str(f) + "_" + str(iy) + str(iy) + ".jpg", split_pic)
            cy = cy + int(h/split_y)
        cy = 0
        cx = cx + int(w/split_x)

試したこと

最初はimgがNoneになってしまったのですが、今度はタプルに関するエラーになってしまいました。
いつもimreadやshapeのところでエラーが出てしまいます。
一つの画像ではできたので、forや変数で画像を指定はできないのかなど考えましたが、よくわかりません、
よろしくお願いいたします。

追記

bunkatu
├hukuzawa.jpg
├noguti.jpg
├saigo.jpg
└sample.py

というようなフォルダになっているのですが、一つ目の画像はうまく分割されているのですが、二つ目以降おかしなところで分割されています。
そこでエラーも出て止まってしまいました。

0 likes

3Answer

for文の中のcv2.imreadのかっこの位置がおかしいですね。

for f in files:
    print(f)
    img = cv2.imread(f), cv2.IMREAD_COLOR # ここがタプルになっています
    print(img)
    h,w = img.shape[:2]
    print(h)

正しくは

img = cv2.imread(f, cv2.IMREAD_COLOR)

ではないでしょうか?
投稿時のコピーミスだったらすみません。

0Like

Comments

  1. @tkr4649

    Questioner

    ありがとうございます。
    ご指摘の箇所を直すと確かにタプルのエラーは消えましたが、また新しいエラーが出てしまいました。
    imgがないようなのですが...
    下にエラーを載せますので教えてただけないでしょうか。

新しいエラーが出てしまいました。
今までのimgがNoneと出るエラーとは少し違いますが、imgがないようです、、、

OpenCV(4.5.3) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-sn_xpupm\opencv\modules\imgcodecs\src\loadsave.cpp:803: error: (-215:Assertion failed) !_img.empty() in function 'cv::imwrite'
0Like

新しいエラーが出てしまいました。
今までのimgがNoneと出るエラーとは少し違いますが、imgがないようです、、、

cxcyは画像ごとにリセットされる必要があるので、初期化はfor文の中で行ってあげるとよいです。

修正後は以下のようになります。
なお、分割前と分割後の画像はそれぞれbeforeafterディレクトリに格納するようにしています。

# coding: utf-8
import cv2
import os
import glob as g

files = g.glob("./before/*.jpg")

split_x = 3
split_y = 3

for f in files:
	# ファイル名
	print(f)
	# 画像読込
	img = cv2.imread(f, cv2.IMREAD_COLOR)
	# サイズを取得
	h, w, _ = img.shape
	# 拡張子なしファイル名を取得
	src_name = os.path.splitext(os.path.basename(f))[0]
	# 分割幅
	dx = int(w / split_x)
	dy = int(h / split_y)
	# 分割の実行
	cx, cy = 0, 0
	for j in range(split_x):
		for i in range(split_y):
			split_pic = img[cy:cy + dy, cx:cx + dx, :]
			cv2.imwrite(f"./after/{src_name}_{i}{j}.jpg", split_pic)
			cy += dy
		cx += dx
		cy = 0

また、cxcyのような自作インクリメントは二次元配列ともなると複雑です。
私なら以下のようにします。ご参考までに。

# coding: utf-8
import cv2
import os
import glob as g

files = g.glob("./before/*.jpg")

split_x = 3
split_y = 3

for f in files:
	# ファイル名
	print(f)
	# 画像読込
	img = cv2.imread(f, cv2.IMREAD_COLOR)
	# サイズを取得
	h, w, _ = img.shape
	# 拡張子なしファイル名を取得
	src_name = os.path.splitext(os.path.basename(f))[0]
	# 分割幅
	dx = int(w / split_x)
	dy = int(h / split_y)
	# 分割の実行
	for j in range(split_x):
		for i in range(split_y):
			split_pic = img[i * dy: (i + 1) * dy, j * dx:(j + 1) * dx, :]
			cv2.imwrite(f"./after/{src_name}_{i}{j}.jpg", split_pic)
0Like

Comments

  1. @tkr4649

    Questioner

    >cxとcyは画像ごとにリセットされる必要があるので、初期化はfor文の中で行ってあげるとよいです。

    ありがとうございます!!
    解決しました。

Your answer might help someone💌