How to implement custom icons for my script/addon?
Since 2.75 the python API allows for custom icons.
You can store custom icons and load them with bpy.utils.previews.ImagePreviewCollection class, which works like a dictionary.
First let's create such icon dictionary:
import bpy.utils.previews
icons_dict = bpy.utils.previews.new()

Next, we need to find path to our icons. Its best to put them inside a folder named 'icons' next to the script file:
import os
# this will work for addons 
icons_dir = os.path.join(os.path.dirname(__file__), &quot;icons&quot;)
# but it won't give you usefull path when you opened a file in text editor and hit run.
# this will work in that case:
script_path = bpy.context.space_data.text.filepath
icons_dir = os.path.join(os.path.dirname(script_path), &quot;icons&quot;)

Finally load icon.png into the dictionary. Blender uses 32x32 icons in UI:
icons_dict.load(&quot;custom_icon&quot;, os.path.join(icons_dir, &quot;icon.png&quot;), 'IMAGE')

Reference the icon by it's ID, use like this inside UI elements:
icon_value=icons_dict[&quot;custom_icon&quot;].icon_id


It's best to handle loading of icons in the register function, clearing the icons in unregister function, and storing them in a global variable.
If enabled as an addon the filepath of __init__.py is the module variable __file__ in __init__.py and as shown can be converted to a directory path using os.path.dirname(__file__) to get the path to my_addon
Make an add-on with multiple python files to keep our addon's icons neatly contained in our addon's folder.
my_addon/
    __init__.py
    icons/
        icon.png

To test when running from text editor can  add an icons folder to some known path, for example the Desktop folder
Desktop/
    icons/
        icon.png 

and change the code below accordingly to be its absolute path (in this example case /home/user/Desktop/), or  the saved path of the text file, or that of the blend file.
bl_info = {
    &quot;name&quot;: &quot;Custom Icon Test&quot;,
    &quot;author&quot;: &quot;Your Name Here&quot;,
    &quot;version&quot;: (1, 0),
    &quot;blender&quot;: (2, 80, 0),
    &quot;location&quot;: &quot;View3D &gt; UI &gt; Tools&quot;,
    &quot;description&quot;: &quot;Test custom icons&quot;,
    &quot;warning&quot;: &quot;&quot;,
    &quot;doc_url&quot;: &quot;&quot;,
    &quot;category&quot;: &quot;Testing&quot;,
}

import os
import bpy
import bpy.utils.previews

class CUSTOM_PT_myPanel(bpy.types.Panel):
    bl_label = &quot;My Icon Panel&quot;
    bl_idname = &quot;OBJECT_PT_custom_panel&quot;
    bl_space_type = &quot;VIEW_3D&quot;   
    bl_region_type = &quot;UI&quot;
    bl_category = &quot;Tools&quot;

    def draw(self, context):
        global custom_icons
        self.layout.label(text=&quot;Blender SE&quot;, icon_value=custom_icons[&quot;custom_icon&quot;].icon_id)

# global variable to store icons in
custom_icons = None

def register():
    global custom_icons
    custom_icons = bpy.utils.previews.new()
    addon_path =  os.path.dirname(__file__)
    icons_dir = os.path.join(addon_path, &quot;icons&quot;)
    
    custom_icons.load(&quot;custom_icon&quot;, os.path.join(icons_dir, &quot;icon.png&quot;), 'IMAGE')
    bpy.utils.register_class(CUSTOM_PT_myPanel)

def unregister():
    global custom_icons
    bpy.utils.previews.remove(custom_icons)
    bpy.utils.unregister_class(CUSTOM_PT_myPanel)

if __name__ == &quot;__main__&quot;:
    # Test run
    # edit to folder containing your icons folder
    __file__ = &quot;/home/user/Desktop/&quot;
    # The path of this text (if saved)
    #__file__ = bpy.context.space_data.text.filepath
    # The path of this blend file (if saved)
    #__file__ = bpy.data.filepath
    register()

Result: