Image Annotation Page

From CSclasswiki
Jump to: navigation, search




Annotating Points on Images

--Jbyun 11:25, 13 April 2015 (EDT)

  • This program works with any gif image
  • Essentially it works in this fashion:
    • On the menu bar, click File -> Open and a window pops up to select an image from a directory
    • Once you click on the image, enter any description and that information will be saved into a CSV file
    • This information will be sorted so that the labels are displayed in an orderly fashion
    • To quit, click the red X button in the top left corner of the window


    # imageAnnotation.py
    # Jackie Byun, 2017
    # This program runs on a python applet format where the user can open a gif image from the directory and annotate
    # that image by clicking and entering information.
    # The user can clear the canvas (all work is saved on each image's corresponding CSV file)
    # and then open another gif file to start a new project
    # Please remember to always clear the canvas before opening a new file
    
    from tkinter import *
    from tkinter.filedialog import askopenfilename
    
    from tkinter.simpledialog import *
    import csv
    import webbrowser
    
    root = None
    
    # UI inherits from a Frame
    class UI: #( Frame ):
    
        def __init__( self, width, height, root=None ):
            self.root   = root
            self.width  = width
            self.height = height
            self.currentFileName = None
            
            # create a menu
            self.menubar = Menu( self.root )
            menu = Menu(self.menubar, tearoff=0)
            self.menubar.add_cascade( label="File", menu=menu)
            menu.add_command( label="Open", command=self.openAndDisplayFiles )
            menu.add_command( label="Clear", command=self.clearCanvas)
            menu = Menu(self.menubar, tearoff=0)
            self.root.config( menu=self.menubar)
      
            # create a canvas
            self.canvas = Canvas(self.root, bg="white", width=self.width, height=self.height,
                                 bd=0, highlightthickness=0)
            
            # call annotate function when user clicks on the image
            self.canvas.bind("<Button-1>",self.annotate)
            
            # create hyperlink
            txt = Text( self.root, height=1, width=50 )
            txt.pack(anchor=NE,expand=False)
            txt.insert( END, "Click here", ('link',str(0)))
            txt.insert( END, " for the Smith Visual Culture website." )
            txt.tag_config( 'link', foreground = "blue", underline=1 )
            txt.tag_bind( 'link', '<Button-1>', self.showLink )     #call showLink function when link is clicked
        
            # create the picture frame
            self.pictureFrame = Frame( self.root, bg="red" )
            self.pictureFrame.pack(side=LEFT)
            
            # create the frame for the entries
            self.entryFrame = Frame( self.root )
            self.canvas.create_window( 700, 10, window=self.entryFrame,anchor=NE, width=180)
            
            # fill the canvas
            self.canvas.pack( fill = "both" )
    
    
    
        # call askopenfilename to select gif from directory and then read and display its csv file contents
        def openAndDisplayFiles( self ):
            fileName = askopenfilename( )
            words = fileName.rsplit('/')
            self.currentFileName = words[-1]                        #currentFileName is the gif image name
            self.csvFileName = self.currentFileName + ".csv"
            path = "/".join(words[0:-1]) + "/"                      #path is the directory to save a csv file if needed
            print( "openFile called: ", self.currentFileName )
    
            # create photo and display it
            self.photo = PhotoImage( file = self.currentFileName )
            self.canvas.create_image( 20, 10, image = self.photo, anchor = NW )
    
            # call function
            self.readAndDisplayCSVFile()
    
    
    
        # open csv file and create its labels
        def readAndDisplayCSVFile( self ):
            sortedList = []
            
            #check if csv file exists in directory
            try:
                #sort each line in the file by their y value location
                for line in open(self.csvFileName,"r"):
                    x,y,text = line.split(",")
                    x = int(x.strip())
                    y = int(y.strip())
                    sortedList.append((y,x,text))
                sortedList.sort()
                for d,(y,x,text) in enumerate(sortedList):
                    self.createLabel(text,x,y)
    
            #if not, then create a new empty csv file
            except:
                newfile = open(self.csvFileName,"w").write("")
    
                        
    
        # create each label with a line connecting it to the area clicked
        def createLabel( self, text, inX, inY ):
            #create label widgets
            label = Label( self.entryFrame, padx=10, pady=10,
                           relief=GROOVE, justify=LEFT, wraplength=160,
                           text = text, anchor=NE)
            self.entryFrame.update()
            label.pack( fill=None, expand=False,anchor=W)
            
            #draw dot on coordinates clicked
            dot = self.canvas.create_oval(inX-3,inY-3,inX+3,inY+3,fill="black")
    
            #draw line connecting the label to dot
            line = self.canvas.create_line((self.width - self.entryFrame.winfo_width()),
                                            self.entryFrame.winfo_height()+35,
                                            inX, inY, activefill="green" )
    
    
            
        # clears features drawn on the canvas and set up the entryframe
        def clearCanvas( self ):
            self.canvas.delete(ALL)
    
            # recreate the frame for the entries
            self.entryFrame = Frame( self.root )
            self.canvas.create_window( 700, 10, window=self.entryFrame,anchor=NE, width=180)
    
        
    
        # annotate function: called when the user clicks in the window
        def annotate(self,event):
            # do not annotate on clicks outside the image
            if (event.x < 20 or event.y < 10):
                return
            if (event.x > self.photo.width() + 20 or event.y > self.photo.height()+ 10):
                return
            
            # draw x mark where mouse clicked
            line1 = self.canvas.create_line(event.x+5,event.y-5,event.x-5,event.y+5,width=4,fill="black")
            line2 = self.canvas.create_line(event.x-5,event.y-5,event.x+5,event.y+5,width=4,fill="black")
    
            description = askstring("Input","Enter Description")
    
            # if entry box is none or exited, remove mouse click mark
            if (description == None):
                self.canvas.delete(line1)
                self.canvas.delete(line2)
                return
    
            # append new annotation to csv file
            file = open(self.csvFileName,"a")
            file.write("%d,%d,%s\n" % (event.x,event.y,description))
            file.close()
    
            # clear the canvas to redraw new information
            self.clearCanvas()
    
            # recreate the picture frame
            self.pictureFrame = Frame( self.root, bg="red" )
            self.pictureFrame.pack(side=LEFT)
    
            # redraw image, labels, and lines
            self.canvas.create_image( 20, 10, image = self.photo, anchor = NW )
            self.readAndDisplayCSVFile()
    
            
    
        # connect hyperlink to browser
        def showLink( self, event ):
            links     = ["http://www.smith.edu/vistas/"]
            idx = int( event.widget.tag_names( CURRENT )[1] )
            webbrowser.open_new( r"%s" % links[idx] )
    
    
    
    def main():
        root = Tk()
    
        # create the window
        app = UI( 750, 500, root )
    
        # main event loop
        root.mainloop()
    
    main()
    

Screenshot of Canvas Window

Screenshot 2015-04-13 11.29.35.png

CSV Text File

  • This is the CSV file that is created from code provided above
  • The file name is whatever the gif image name is with a .csv extention


227,67,a window to the outdoors! What a lovely garden she has
132,111,She is decorated with diamond necklaces and head ordinates. How beautiful
136,304,This gown makes it look like she's ready to go to the ball!