Python Forum
How to extract (x,y) coordinates of the boundary of a .tif image?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to extract (x,y) coordinates of the boundary of a .tif image?
#11
(Feb-06-2017, 03:02 AM)Skaperen Wrote: do you want every pixel or just the points to draw lines from and to?
every pixel on the red line.
Reply
#12
does the image contain actual red lines or do you need to find a boundary (some graphical algorithm needed)?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#13
(Feb-09-2017, 03:17 AM)Skaperen Wrote: does the image contain actual red lines or do you need to find a boundary (some graphical algorithm needed)?

I just need the boundary of this TIF image (copy and paste this URL, its in dropbox) - goo.gl/Uai8lR
Reply
#14
Maybe this can help you?
http://scikit-image.org/docs/dev/api/ski...d_contours

Edit: some 'quick and dirty' solution based on what they describe in scikit:
import PIL
import PIL.Image

ima = PIL.Image.open("Bild90.tif")
imsize = ima.size
boundary = []
for imapp in range(imsize[0] -1):
    for imapix in range(imsize[1] -1):
        pix1 = ima.getpixel((imapp, imapix))
        pix2 = ima.getpixel((imapp, imapix +1))
        pix3 = ima.getpixel((imapp + 1, imapix))
        pix4 = ima.getpixel((imapp + 1, imapix +1))
        if not (pix1 == pix2 == pix3 == pix4):
            boundary.append((imapp, imapix))

imac = ima.copy()
imacopy = imac.convert("L")
for pixel in boundary:
    imacopy.putpixel(pixel, 255)

imacopy.show()
If the boundary needs to be only one pixel wide, one has to refine it a bit further.
Reply
#15
that seems to be a one to two hour project once one has direct pixel access.  i've only done such things in c before.  i am interested in that kind of thing in python.

why tif?  if i had control over what is making these images, i'd rather use png format.  either way, once you have pixels, it should be doable not too hard.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
Reply
#16
(Feb-09-2017, 05:35 PM)merlem Wrote: If the boundary needs to be only one pixel wide, one has to refine it a bit further.
Yes, the boundary needs to be just one pixel wide, could you please refine it?
How do I get to save the coordinates of the boundary?
Reply
#17
The pixels are held as tuples in the list 'boundary'. You can view them or save them like other objects in python.

I'll try to refine the code, but I'm not sure how long it will take. There are some tricky places where the boundary goes 'backwards' again, that may rise some problems.
Reply
#18
Welll... it is tricky.
I can check for some patterns, but a rest remains that is more difficult to handle. So I decided to call upon human pattern recognition for the difficult ones.

It is still a quite 'quick and dirty' code, one could certainly find a lot of things to do better. But it seems to work at least.


# -*- coding: cp1252 -*-
import PIL
import PIL.Image
 
# some preparation steps:
# open the image
ima = PIL.Image.open("Bild90.tif")
# and take two Kopies for demonstration purposes
imac = ima.copy()
imacopy = imac.convert("L")
 
 
# get image data
imsize = ima.size
bgcol = ima.getpixel((0, 0))        # this is the colour in the upper left edge 
areacol = ima.getpixel((imsize[0] - 1, imsize[1] - 1))
                                    # this is the colour in the lower right edge 
 
# lists for later use
wideboundary = []                   # to hold all blue pixels with black neigbours 
provenpixels = []                   # to hold all proven boundary pixels 
unprovenpixels = []                 # to hold pixels for another check
edgepatpixels = []
 
# now go to work
for pix_x in range(imsize[0]):
    wideboundary.append([])         # make a new list for every image column
    for pix_y in range(imsize[1]):
        # to be a border pixel, it has to be blue, that is, not of bgcol
        if ima.getpixel((pix_x, pix_y)) != bgcol:
            # and it has to have at least one black neighbour
            neighbourhood = [(pix_x - 1, pix_y - 1), (pix_x - 1, pix_y),
                        (pix_x - 1, pix_y + 1), (pix_x, pix_y - 1),
                        (pix_x, pix_y + 1), (pix_x + 1, pix_y - 1),
                        (pix_x + 1, pix_y), (pix_x + 1, pix_y * 1)]
            for neighbourpix in neighbourhood:
                try:
                    if ima.getpixel(neighbourpix) == bgcol:
                        # append to the last list in wideboundary
                        wideboundary[-1].append((pix_x, pix_y))
                        break
                except IndexError:  # the first and the last image col lack
                    pass            # some of the neighbours
 

# now try to reduce to a 1-pixel-border
# the first case ia an easy one: if an image column has only 1 pixel, it's okay
for pixelgroup in wideboundary:
    if len(pixelgroup) == 1:
        provenpixels.append(pixelgroup[0])
    elif len(pixelgroup) == 2:
        #print "2er-pixelgroup: ", pixelgroup
        # then the upper pixel will be the border pixel
        if pixelgroup[0][1] > pixelgroup[1][1]:
            if pixelgroup[0][1] - pixelgroup[1][1] == 1:
                provenpixels.append(pixelgroup[1])
            else:
                unprovenpixels.append(pixelgroup)
        elif pixelgroup[0][1] < pixelgroup[1][1]:
            if pixelgroup[1][1] - pixelgroup[0][1] == 1:
                provenpixels.append(pixelgroup[0])
            else:
                unprovenpixels.append(pixelgroup)
    else:
        unprovenpixels.append(pixelgroup)

stillunprovpixels = []
# another pattern that is quite good to recognize is having three bgcol
# neighbours 'over edge'
for pixgp in unprovenpixels:
    for pix in pixgp:
        pix_x = pix[0]
        pix_y = pix[1]
        for pattern in [[(pix_x - 1, pix_y - 1), (pix_x - 1, pix_y),
                   (pix_x, pix_y - 1)],
                  [(pix_x -1, pix_y), (pix_x - 1, pix_y + 1),
                   (pix_x, pix_y + 1)],
                  [(pix_x, pix_y - 1), (pix_x + 1, pix_y - 1),
                   (pix_x + 1, pix_y)],
                  [(pix_x, pix_y + 1), (pix_x + 1, pix_y + 1),
                   (pix_x + 1, pix_y)] ]:
            patchecks = []
            for patpix in pattern:
                try:
                    if ima.getpixel(patpix) == bgcol:
                        patchecks.append(True)
                except IndexError:  # the first and the last image col lack
                    pass            # some of the neighbours
            if patchecks == [True, True, True]:
                if not pix in provenpixels:
                    provenpixels.append(pix)
            
        if not pix in provenpixels and not pix in stillunprovpixels:
                    stillunprovpixels.append(pix)
        

# a third pattern: having three bgcol neighbours at one side makes a pixel
# being a borderpixel
stillunprovpix = []
for supix in stillunprovpixels:
    pix_x = supix[0]
    pix_y = supix[1]
    nopattern = True
    for pattern in [[(pix_x - 1, pix_y - 1), (pix_x - 1, pix_y),
               (pix_x - 1, pix_y + 1)],
              [(pix_x + 1, pix_y - 1), (pix_x + 1, pix_y),
               (pix_x + 1, pix_y + 1)],
              [(pix_x - 1, pix_y - 1), (pix_x, pix_y - 1),
               (pix_x + 1, pix_y - 1)],
              [(pix_x - 1, pix_y + 1), (pix_x, pix_y + 1),
               (pix_x + 1, pix_y + 1)] ]:
        if bgcol == ima.getpixel(pattern[0]) == ima.getpixel(pattern[1]) \
                    == ima.getpixel(pattern[2]):
            nopattern = False
    if nopattern == False:
        if not pix in provenpixels:
                provenpixels.append(supix)
    else:
        stillunprovpix.append(supix)

shortunprovpixels = []
# the edge pattern, 'shifted' by one, could be a good pixel reduction pattern
for supix in stillunprovpixels:
    pix_x = supix[0]
    pix_y = supix[1]
    if not ima.getpixel(pix) != bgcol:
        print "Pixelalarm"
    for pattern in [[(pix_x - 1, pix_y), (pix_x, pix_y - 1)],
              [(pix_x -1, pix_y), (pix_x, pix_y + 1)],
              [(pix_x, pix_y - 1), (pix_x + 1, pix_y)],
              [(pix_x, pix_y + 1), (pix_x + 1, pix_y)] ]:
        for patpix in pattern:
            try:
                if (ima.getpixel(pattern[0]) == ima.getpixel(pattern[1])) \
                    and ima.getpixel(pattern[0]) != bgcol:
                    pass
                else:
                    if not pix in provenpixels:
                        shortunprovpixels.append(supix)
            except IndexError:  # the first and the last image col lack
                pass            # some of the neighbours

# do some cleanup:
remainingunclear = []
for pix in shortunprovpixels:
    if pix not in provenpixels and pix not in remainingunclear:
        remainingunclear.append(pix)

# now, the patterns become very diverse... so I wonder whether I may
# ask the user himself to decide
# it's a bit tedious, I confess, however...
text = ("For each unproven pixel, please decide whether this pixel belongs to \
the border. An image will be shown with the pixel in question being \
marked white, already proven pixels are shown in grey. Close each image to \
continue. (Usually, pressing ESC should do.) \n \
And now press 'enter' to continue.")
print text
raw_input()
for provenpix in provenpixels:
    imacopy.putpixel(provenpix, 175)
for stillunprovpix in remainingunclear:
    imacopy.putpixel(stillunprovpix, 75)
 
for stillunprovpix in remainingunclear:
    imacopy.putpixel(stillunprovpix, 255)
    imacopy.show()
    print "Is this a border pixel? It has the coordinates: ", stillunprovpix
    while True: 
        pixelinfo = raw_input("yes (y) or no (n)? ")
        if pixelinfo in ("y", "ye", "yes"):
            provenpixels.append(stillunprovpix)
            imacopy.putpixel(stillunprovpix, 175)
            break
        elif pixelinfo in ("n", "no"):
            imacopy.putpixel(stillunprovpix, 100)            # remove mark
            break
 
print "The borderline pixels are: "
print provenpixels
 
##The borderline pixels are: 
##[(1, 9), (3, 10), (4, 10), (5, 10), (7, 9), (9, 8), (10, 8), (13, 10),
##(15, 11), (16, 11), (20, 5), (21, 5), (22, 5), (23, 5), (24, 5), (25, 5),
##(26, 5), (27, 5), (29, 4), (30, 4), (31, 4), (32, 4), (34, 5), (36, 9),
##(38, 8), (40, 9), (41, 9), (44, 6), (45, 6), (47, 7), (48, 7), (49, 7),
##(50, 7), (51, 7), (54, 9), (56, 10), (57, 10), (58, 10), (59, 10), (60, 10),
##(65, 5), (66, 5), (69, 5), (70, 5), (72, 6), (73, 6), (76, 10), (77, 10),
##(78, 10), (83, 4), (84, 4), (85, 4), (86, 4), (87, 4), (88, 4), (90, 3),
##(94, 6), (96, 7), (97, 7), (98, 7), (99, 7), (100, 7), (102, 9), (103, 9),
##(104, 9), (105, 9), (106, 9), (108, 8), (110, 7), (111, 7), (112, 7), (113, 7),
##(118, 11), (119, 11), (120, 11), (121, 11), (125, 7), (0, 8), (2, 9), (6, 9),
##(8, 8), (11, 8), (12, 9), (14, 10), (17, 10), (18, 6), (19, 5), (28, 4),
##(33, 4), (35, 5), (37, 8), (39, 8), (42, 8), (43, 6), (46, 6), (52, 7), (53, 8),
##(55, 9), (61, 9), (62, 7), (63, 6), (64, 5), (67, 4), (68, 4), (71, 5), (75, 6),
##(75, 9), (79, 5), (80, 6), (82, 4), (89, 3), (91, 3), (92, 4), (93, 5), (95, 6),
##(101, 7), (107, 8), (109, 7), (114, 7), (115, 8), (116, 9), (117, 10),
##(122, 10), (123, 9), (124, 7), (126, 6), (0, 8), (2, 9), (6, 9), (8, 8),
##(11, 8), (12, 9), (14, 10), (17, 10), (18, 6), (18, 7), (18, 8), (18, 9),
##(19, 5), (28, 4), (33, 4), (35, 5), (35, 6), (35, 7), (35, 8),
##(37, 8), (39, 8), (42, 8), (43, 6), (43, 7), (46, 6), (52, 7), (53, 8),
##(55, 9), (61, 9), (62, 7), (62, 8), (63, 6), (64, 5), (67, 4), (68, 4), (71, 5),
##(74, 6), (74, 7), (74, 8), (75, 9), (79, 5), (79, 10), (80, 5),
##(80, 6), (80, 10), (81, 5), (81, 7), (81, 8), (81, 9), (82, 4), (89, 3),
##(91, 3), (92, 4), (93, 5), (95, 6), (101, 7), (101, 8), (107, 8), (109, 7),
##(114, 7), (115, 8), (116, 9), (117, 10), (122, 10), (123, 9), (124, 7),
##(124, 8), (126, 6)]
Does this do what it should?
Reply
#19
I can't differentiate the color of new pixel and already proven pixel, they all look same color to me. Am I missing something?
Reply
#20
Oh? Usually, the pixel colours should be different enough.
bgcol is 0 when I ask for the numeric value here, referring to black.
The pixels whose borderstate has been proven have colour 175, the is a light grey.
The 'stillunprovenpixels' are dark grey instead with a colour of 75. (That's a total of approximately a dozen.)
And I set the value for the 'pixel in question' to 255, that should be pure white. The first one is in column 19, the lower end of four vertical border pixels.

Strange Huh . If necessary, I will have to change to RGB colours, I guess.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Get the image's coordinates not the canvas' when navigate on an image hobbyist 9 1,778 Jul-21-2022, 03:29 PM
Last Post: deanhystad
  Crop Image to Bounding Box Coordinates sallyjc81 2 4,945 Jul-23-2020, 08:46 AM
Last Post: sallyjc81
  periodic boundary contions grknkilicaslan 1 1,857 Jul-18-2020, 10:16 PM
Last Post: Gribouillis
  How to extract temperature value of pixels of a thermal image recorded by IR camera hamacvan 1 14,380 Jan-13-2019, 06:06 PM
Last Post: Larz60+
  How to extract digits in table of image using python SuSeegio 3 3,028 Dec-05-2018, 10:47 AM
Last Post: Larz60+

Forum Jump:

User Panel Messages

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