Python Forum
Help developing img cropping tool in python
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help developing img cropping tool in python
#1


Hi everyone

I am trying to develop a python script that can crop multiple images from one image and export each crop to a new image. The purpose is to "cut out" pieces for boardgames for future development. I'll try to be very specific as what I need it to do / where I'm at in development.

below is an example of the file I need to crop. I need a script to basically crop each piece, and export that piece to a new png file with a new name. doing this by hand is excruciating, hence why im trying to use python.

[Image: pic594563_md.jpg]

now here's where I'm at with my code so far using the PIL library, which allows for image processing. If anyone can help me out with this, it would be super appreciated, I have several paid jobs coming up involving this and would be amazing if I could cut hours out of the development process.

# wargame counter cutter
# developed by Ray Weiss

# import image class
from PIL import Image
# command line arguments
from sys import argv

# bringing in arguments from command line, defines numbers for program
filename = argv[1]
vert_to_counter = argv[2]
horiz_to_counter = argv[3]
counter_size = argv[4]
counters_in_a_row = argv[5]
rows_of_counters = argv[6]
columns_of_counters = argv[7]

i = 0  # reserving use as iterators
r = 0

img = Image.open(filename)
new_counters = ()
new_image_number = 1

while i != (rows_of_counters + 1) and r != (columns_of_counters + 1):

    new_img = img.crop((vert_to_counter, horiz_to_counter, 72, 72))
from here im a little stumped, I figure I have to supply the program several arguments as specified to get it to work, but now I am at a loss as to what to do.

Thanks!
Ray
Reply
#2
Not quite clear on what problem you are having.
What part of this are you struggling with?

Just wrote up a quick thing to cut up one of my sprite sheets and it works quite well with just PIL:
import os
from PIL import Image


savedir = "results"
filename = "axodeath.png"
frame_size = (200, 100)
columns = 5
rows = 4

img = Image.open(filename)


frame_num = 1
width, height = frame_size
for col in range(columns):
    for row in range(rows):
        x, y = width * col, height * row
        crop = img.crop((x, y, x+width, y+height))
        crop.save(os.path.join(savedir, "frame_{:02}.png".format(frame_num)))
        frame_num += 1
This cuts my 5x4 sprite sheet with images that are each (200, 100) pixels into individual frames and then saves them.
Reply
#3
I suppose I am having trouble trying to come up with an algorithm or solution that will work but i'll take a look at yours, thank you! Mostly I suppose I am looking for help/guidance in how I would go about doing this, not sure where to start, but your example should help, thank you! (im fairly terrible at math so this is a little difficult for me to grokk)

For example

# wargame counter cutter
# developed by Ray Weiss

# import image class
from PIL import Image
# command line arguments
from sys import argv

# bringing in arguments from command line, defines numbers for program
filename = argv[1]
vert_to_counter = argv[2]
horiz_to_counter = argv[3]
counter_size = argv[4]
counters_in_a_row = argv[5]
rows_of_counters = argv[6]
columns_of_counters = argv[7]
group_columns = argv[8]

# keeping track of where the program is on a counter sheet
current_row = 0
current_column = 0
current_group = 0
current_counter = 1

# container for counters, tuple because order does not matter
new_counters = ()
# open file specified in argument
img = Image.open(filename)

while current_row != (rows_of_counters+ 1) and \
  current_column != (columns_of_counters + 1) and \
  current_group != (group_columns+ 1):
    row_finished = False
    new = img.crop(vert_to_counter, vert_to_counter, 72, 72)
    new.save(f"img:{current_counter}")
    if current_counter > counters_in_a_row:
        current_counter = 0
        current_row += 1
Here is where I am now, I have a procedure to figure this out in my head, but im not sure how to translate it to python. here is the algorithm.

open file
jump pointer the distance of the sheet edge, to the counter, horizontally and vertically
cut out a counter
export it under a new name
if current column > total columns, reset column to 0, add 1 to current row
reset pointer to first counter in the following row
check if last row
if last row, check if current group column => group columns
if yes, end program, if not, move pointer to start of second group
otherwise if all of the above are false:
repeat the process on the next counter to the right

does that make some sense?
Reply
#4
I would myself definitely use for loops rather than while loops for this.
Also you need to reexamine what arguments Image.crop takes.

You wrote:
new = img.crop(vert_to_counter, vert_to_counter, 72, 72)
Firstly it takes one argument that is a tuple, and secondly the last two parts of that tuple are not height and width but rather, right and bottom of the desired box.
crop = img.crop((x, y, x+width, y+height))

If you can give me a full rez copy of one of your images I'll try to give you an example implementation.
Reply
#5
(Dec-18-2017, 12:35 PM)Mekire Wrote: I would myself definitely use for loops rather than while loops for this.
Also you need to reexamine what arguments Image.crop takes.

You wrote:
new = img.crop(vert_to_counter, vert_to_counter, 72, 72)
Firstly it takes one argument that is a tuple, and secondly the last two parts of that tuple are not height and width but rather, right and bottom of the desired box.
crop = img.crop((x, y, x+width, y+height))

If you can give me a full rez copy of one of your images I'll try to give you an example implementation.

thank you so much!

yeah it's been a while since I coded with python and have been doing a lot of rust lately, so I figured I would be off a little bit, thank you again for your help though, here is a link to a sample file https://drive.google.com/file/d/1PKI4FrK...sp=sharing
Reply
#6
Well, one of the main issues here is your input images (assuming they are all like this) are not perfect.  Lines aren't quite straight so you can only approximate.

This gives a pretty good cut for this specific sheet and should give you the idea how to do this:
import os
from PIL import Image


savedir = "results"
filename = "testcounters.png"
img = Image.open(filename)


start_pos = start_x, start_y = (54,81)
frame_size = w, h = (91, 90)

major_columns = 2
major_column_w = 1010
major_rows = 5
major_row_h = 228
columns = 10
rows = 2

frame_num = 1
w, h = frame_size
for col_m in range(major_columns):
    for row_m in range(major_rows):
        for row in range(rows):
            for col in range(columns):
                x = w*col + start_x + major_column_w*col_m
                y = h*row + start_y + major_row_h*row_m
                crop = img.crop((x, y, x+w, y+h))
                save_at_template = os.path.join(savedir, "counter_{:03}.png")
                crop.save(save_at_template.format(frame_num))
                frame_num += 1
Code should obviously be cleaned up and put in functions.
Reply
#7
Awesome! This is just what I needed to get going on my own, thank you so much, I really appreciate it!

Quick question, could you kindly comment out what some of the variables are in your for loop? I think I can guess the others. I figure if I switch it around to have the width height values taken from GIMP or the command line, then it could be tailored to the sheet.
Reply
#8
start_pos = start_x, start_y = (54,81) # Coordinates of first cell
frame_size = w, h = (91, 90) # Size of each cell

major_columns = 2 # Number of pages
major_column_w = 1010 # Width between cell to cell on next page 
major_rows = 5 # Number of blocks per page
major_row_h = 228 # Height between cell to cell on next block 
columns = 10 # Columns per block
rows = 2 # Rows per block
Reply
#9
So here's a follow up question, I switched it from user input to just take input from a txt file to speed up debugging time. I can get this code to run, but its not reading any of the numbers ive put into the txt file, this has been killing me for hours, if anyone can help its really appreciated

############################################
#
#
#       WARGAME COUNTER-CUTTER
#       Programmed by Ray Weiss
#       [email protected]
#
#
############################################

#  imports

import os
from PIL import Image
from sys import argv

save_dir = "results"
filename = argv[1]  # Your counter sheet
img = Image.open(filename)

if not os.path.exists(save_dir):
    os.makedirs(save_dir)

with open("instr.txt") as f:
    line = f.readline()
    out = line.strip("\n")

    while line:
        line = f.readline()
        out = line.strip("\n")
        start_pos = start_x, start_y = [int(x) for x in out.split(",")]
        counter_size = w, h = [int(x) for x in out.split(",")]
        line = f.readline()
        out = line.strip("\n")
        major_columns = int(out)
        line = f.readline()
        out = line.strip("\n")
        major_columns_w = int(out)
        line = f.readline()
        out = line.strip("\n")
        major_rows = int(out)
        line = f.readline()
        out = line.strip("\n")
        major_rows_h = int(out)
        line = f.readline()
        out = line.strip("\n")
        columns = int(out)
        line = f.readline()
        out = line.strip("\n")
        line = f.readline()
        rows = int(out)


###################################
#
#  End of user supplied arguments
#  Start of program
#
###################################

frame_num = 1

w, h = counter_size

for col_m in range(major_columns):
    for row_m in range(major_rows):
        for row in range(rows):
            for col in range(columns):
                x = w * col + start_x + major_columns_w * col_m
                y = h * row + start_y + major_rows_h * row_m
                crop = img.crop((x, y, x + w, y + h))
                save_at_template = os.path.join(save_dir, "counter_{:03}.png")
                crop.save(save_at_template.format(frame_num))
                frame_num += 1
Reply
#10
Think you will find json a better choice than pure plain text.

Your config file could then look like this:
{
"start_x" : "54",
"start_y" : "81",
"width" : "91",
"height" : "90",
"major_columns" : "2",
"major_column_w" : "1010",
"major_rows" : "5",
"major_row_h" : "228",
"columns" : "10",
"rows" : "2"
}
Then parsing it is simple:
import os
import json

from PIL import Image


savedir = "results"
filename = "testcounters.png"
img = Image.open(filename)
with open("sheetconfig.json") as f:
    data = json.load(f)
data = {k:int(v) for k,v in data.items()}

w, h = data["width"], data["height"]
frame_num = 1
for col_m in range(data["major_columns"]):
    for row_m in range(data["major_rows"]):
        for row in range(data["rows"]):
            for col in range(data["columns"]):
                x = w*col + data["start_x"] + data["major_column_w"]*col_m
                y = h*row + data["start_y"] + data["major_row_h"]*row_m
                crop = img.crop((x, y, x+w, y+h))
                save_at_template = os.path.join(savedir, "counter_{:03}.png")
                crop.save(save_at_template.format(frame_num))
                frame_num += 1
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Question image manipulation (cropping and MetaData) SpongeB0B 4 1,170 Jul-03-2023, 06:35 PM
Last Post: SpongeB0B
  Is there software/tool for coding Python? dee 11 2,870 Jun-14-2022, 02:32 PM
Last Post: dee
  python tool to collect the time measurement of entire code maiya 3 2,324 Feb-12-2021, 05:39 PM
Last Post: BashBedlam
  I need advise with developing a brute forcing script fatjuicypython 11 5,093 Aug-21-2020, 09:20 PM
Last Post: Marbelous
  Best extension for Andriod developing ? samuelbachorik 1 1,608 Apr-29-2020, 01:30 PM
Last Post: Larz60+
  Developing application for Android atari400 1 1,920 Nov-27-2019, 08:31 AM
Last Post: buran
  Python Based Data QA Automation tool suggestion Sonia567 1 2,001 Nov-19-2019, 04:46 PM
Last Post: Larz60+
  Developing Python with OpenCV into an Android App AviationFreak 1 6,836 Sep-29-2019, 08:55 AM
Last Post: wavic
  Getting help on developing a code Masoudk96 1 1,983 Sep-04-2019, 10:48 PM
Last Post: Larz60+
  Python QGIS tool that replaces layout text labels with attributes from an input table geodenn92 1 2,690 Aug-13-2019, 06:05 AM
Last Post: buran

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020