自动从漫画中提取图块

问题描述 投票:0回答:2

是否可以使用 ImageMagick 等现有工具自动从漫画中提取图块,或者我应该自己编写一个工具?

我已经使用 ImageMagick 看到了答案(使用 imagemagick 如何将图像分割成多个单独的图像?https://superuser.com/questions/1308928/how-to-automatically-crop-and-cut- an-image-into-several-images-using-imagemagick/1308953#1308953)但在我的情况下,图块可以具有不同的尺寸(高度可以改变)。

彼此下方始终有 1 个图块(仅 1 列),并且每个图块都由相同颜色的一些空间分隔(可以在图像中使用黑色、灰色或白色的水平颜色渐变来间隔图块),因此应该通过查看具有相同像素颜色的水平线,可以检测何时有新图块并提取它们。

理想情况下,如果漫画有 2 个或更多列,其中的图块高度不同(这可能会更复杂一些,因为不一定有具有相同像素颜色的完整水平线),也应该可以提取图块。

更新:您可以根据要求找到我在下面制作的快速示例。有些漫画有一些字符和文本气泡从图块中出来,这使得无法比较水平线上的像素,所以我特意在示例中添加了它。我还添加了另一列和具有不同宽度或高度的图块,以便获得一个示例,其中包含漫画中可以找到的内容的摘要。

image-processing imagemagick image-manipulation image-recognition imagemagick-convert
2个回答
2
投票

以下是如何在 ImageMagick 中执行此操作。但我注意到你的图可能不具有代表性。首先,我期待的是垂直堆叠的框架,而不是随机排列。其次,部分图形在 X 或 Y 上重叠,以便边界框重叠。我使用连接组件来提取边界框。然后我只需循环边界框并裁剪图像。

输入:

Unix 语法:

bboxArr=(`convert -quiet boxes.png +repage -threshold 50% \
-morphology open square:3 -type bilevel \
-define connected-components:exclude-header=true \
-define connected-components:verbose=true \
-define connected-components:area-threshold=1500 \
-define connected-components:mean-color=true \
-connected-components 4 null: | grep "gray(0)" | awk '{print $2}'`)
num=${#bboxArr[*]}
for ((i=0; i<num; i++)); do
bbox="${bboxArr[$i]}"
echo "$bbox;"
convert -quiet boxes.png +repage -crop "$bbox" +repage boxes_$i.png
done

这是一个更好的例子:

bboxArr=(`convert -quiet DoomPatrol1.jpg +repage -negate -threshold 25% -type bilevel \
-define connected-components:exclude-header=true \
-define connected-components:verbose=true \
-define connected-components:area-threshold=20000 \
-define connected-components:mean-color=true \
-connected-components 8 null: | grep "gray(255)" | awk '{print $2}'`)
num=${#bboxArr}
for ((i=0; i<num; i++)); do
bbox="${bboxArr[$i]}"
echo "$bbox;"
convert -quiet DoomPatrol1.jpg +repage -crop "$bbox" +repage boxes_$i.png
done


0
投票

这里有一些 powershell 魔法可以使长网络漫画变短(使用 ure idea):

# Function to process a single file
function ProcessFile {
    param (
        [string]$originalFilePath,
        [string]$outputDir
    )


    # Get bounding boxes and store in $bboxArr
    $originalFileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($originalFilePath)
    $originalFileDirectory = [System.IO.Path]::GetDirectoryName($originalFilePath)

    $output = magick convert -quiet $originalFilePath +repage -negate -threshold 15% `
      -morphology Dilate Rectangle:1x30+0+0 `
      -type bilevel `
      -define connected-components:exclude-header=true `
      -define connected-components:verbose=true `
      -define connected-components:area-threshold=20000 `
      -define connected-components:mean-color=true `
      -connected-components 8 null: 

    $bboxArr = @()
    $output -split "`n" | Select-String -Pattern "gray\(255\)" | ForEach-Object {
        if ($_ -match "(\d+x\d+\+\d+\+\d+)") {
            $bboxArr += $matches[1]
        }
    }

    # Initialize empty array to store final bounding boxes
    $finalBboxArr = @()

    # Filter out smaller boxes likely to be text
    foreach ($bbox in $bboxArr) {
        $splitBbox = $bbox -split "[x\+]"
        $width = [int]$splitBbox[0]
        $height = [int]$splitBbox[1]

        if ($width -gt 350 -and $height -gt 350) {
            $finalBboxArr += $bbox
        }
    }


    # Initialize an array to hold groups of bounding boxes
    $bboxGroups = @()

    # Sort bounding boxes by their y coordinates
    $sortedBboxArr = $finalBboxArr | Sort-Object {
        $split = $_ -split "[x\+]"
        [int]$split[3]
    }

    # Group bounding boxes while keeping the total height <= 1440
    $currentGroup = @()
    $currentGroupHeight = 0

    foreach ($bbox in $sortedBboxArr) {
        $split = $bbox -split "[x\+]"
        $currentY = [int]$split[3]
        $height = [int]$split[1]

        if (($currentGroupHeight + $height) -le 1440) {
            $currentGroup += $bbox
            $currentGroupHeight += $height
        } else {
            if ($currentGroup.Length -gt 0) {
                $bboxGroups += ,@($currentGroup)
            }
            $currentGroup = @($bbox)
            $currentGroupHeight = $height
        }
    }

    # Add the last group if it's not empty
    if ($currentGroup.Length -gt 0) {
        $bboxGroups += ,@($currentGroup)
    }

    # Crop and concatenate images based on groups of bounding boxes
    for ($i = 0; $i -lt $bboxGroups.Length; $i++) {
        $currentGroup = $bboxGroups[$i]
        $tmpFiles = @()

        for ($j = 0; $j -lt $currentGroup.Length; $j++) {
            $bbox = $currentGroup[$j]
            $tmpFileName = "${originalFileDirectory}\${originalFileNameWithoutExtension}_tmp_${i}_${j}.png"
            magick convert -quiet $originalFilePath +repage -crop $bbox +repage $tmpFileName
            $tmpFiles += $tmpFileName
        }

        $newFileName = "${outputDir}\${originalFileNameWithoutExtension}_${i}.png"
        magick convert -append $tmpFiles $newFileName
        Remove-Item $tmpFiles  # Delete temporary files
    }
}



# Main part of the script
$inputDir = "C:\my_folder_with_images_in_webp_format"
$outputDir = "${inputDir}-cropped"

# Create output directory if it doesn't exist
if (-not (Test-Path $outputDir)) {
    New-Item -ItemType Directory -Force -Path $outputDir
}

# Loop through each .webp file in the input directory
Get-ChildItem -Path $inputDir -Filter *.webp | ForEach-Object {
    $originalFilePath = $_.FullName
    # Call the function to process each file
    ProcessFile -originalFilePath $originalFilePath -outputDir $outputDir
}
© www.soinside.com 2019 - 2024. All rights reserved.