Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions aligner.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,38 @@ def apply_transform_with_mask(
)

return transformed, valid_mask


def _align_single_slice(args: tuple) -> dict:
"""Process a single slice alignment (for multiprocessing).

Args:
args: (index, base_bgr, target_bgr, target_bgra, base_size)

Returns:
dict with index, aligned_image, valid_mask, success, score
"""
index, base_bgr, target_bgr, target_bgra, base_size = args
aligner = Aligner(AlignConfig())

result = aligner.align(base_bgr, target_bgr)

if result['matrix'] is not None:
aligned, valid_mask = aligner.apply_transform_with_mask(
target_bgra, result['matrix'], base_size
)
return {
'index': index,
'aligned_image': aligned,
'valid_mask': valid_mask,
'success': bool(result['success']),
'score': result['score'],
}
else:
return {
'index': index,
'aligned_image': target_bgra.copy(),
'valid_mask': np.full(target_bgra.shape[:2], 255, dtype=np.uint8),
'success': False,
'score': result.get('score', 0.0),
}
57 changes: 26 additions & 31 deletions mask_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
# パスを追加
sys.path.insert(0, str(Path(__file__).parent))

from aligner import Aligner, AlignConfig
from multiprocessing import Pool, cpu_count
from aligner import Aligner, AlignConfig, _align_single_slice
from compositor import Compositor, CompositeConfig
from mask_canvas import MaskCanvas
from preview_widget import PreviewWidget
Expand Down Expand Up @@ -96,45 +97,39 @@ def run(self):
)
items.append(base_item)

# Step 4: Align(各差分ピースを位置合わせ)
total_diff = len(slices) - 1
for i in range(1, len(slices)):
if self.isInterruptionRequested():
self.error.emit("キャンセルされました")
return

progress_pct = 20 + int(70 * i / total_diff)
self.progress.emit(progress_pct, f"位置合わせ中... ({i}/{total_diff})")
# Step 4: Align(並列処理)
self.progress.emit(30, "位置合わせ中(並列処理)...")

# BGRA→BGRに変換してからalign(アルファチャンネル対応)
# 位置合わせ用の引数リスト作成
align_args = []
for i in range(1, len(slices)):
base_for_align = slices[0]
target_for_align = slices[i]
if len(base_for_align.shape) == 3 and base_for_align.shape[2] == 4:
base_for_align = cv2.cvtColor(base_for_align, cv2.COLOR_BGRA2BGR)
if len(target_for_align.shape) == 3 and target_for_align.shape[2] == 4:
target_for_align = cv2.cvtColor(target_for_align, cv2.COLOR_BGRA2BGR)

result = self.aligner.align(base_for_align, target_for_align)

item = SliceItem(index=i, image=slices[i])

if result['matrix'] is not None:
aligned, valid_mask = self.aligner.apply_transform_with_mask(
slices[i], result['matrix'], base_size
)
item.aligned_image = aligned
item.valid_mask = valid_mask
item.alignment_success = bool(result['success'])
item.alignment_score = result['score']
else:
# 行列推定失敗時は元画像を保持
item.aligned_image = slices[i].copy()
item.valid_mask = np.full(slices[i].shape[:2], 255, dtype=np.uint8)
item.alignment_success = False
item.alignment_score = result.get('score', 0.0)

align_args.append((i, base_for_align, target_for_align, slices[i], base_size))

# multiprocessing で並列実行
n_workers = min(len(align_args), max(1, cpu_count() - 1))
with Pool(processes=n_workers) as pool:
results = pool.map(_align_single_slice, align_args)

# 結果をSliceItemに変換
for r in results:
item = SliceItem(
index=r['index'],
image=slices[r['index']],
aligned_image=r['aligned_image'],
valid_mask=r['valid_mask'],
alignment_success=r['success'],
alignment_score=r['score'],
)
items.append(item)

self.progress.emit(95, "並列処理完了")

self.progress.emit(100, "完了")
self.finished.emit((self.job_id, items))

Expand Down