如何安装并运行 GIMP 的 Python 脚本?

如何安装并运行 GIMP 的 Python 脚本?

GIMP 似乎在 2 个目录中查找插件。一个是C:\Program Files\GIMP 2\lib\gimp\2.0\plug-insC:\Users\Sam\AppData\Roaming\GIMP\2.10\plug-ins

在此处输入图片描述

但是,当我查看plug-ins文件夹时,所有内容都是独立的可执行文件,没有 Python 脚本。

我找到了一个我想运行的 Python 脚本。作者说只需将 Python 源代码文件粘贴到plug-ins文件夹中,然后就可以通过菜单在 GUI 中访问该脚本。考虑到文件夹Xtns/Utils中已有的其他内容,这似乎不对plug-ins

'''GIMP plug-in to stitch two images together into a panorama.'''

abort = False

# These should all be standard modules
import sys
import os
import copy
import math
import struct
import time
import gimp
import gimpplugin
from gimpenums import *
import pygtk
pygtk.require('2.0')
import gtk
import cPickle as pickle

#------------ MAIN PLUGIN CLASS

class stitch_plugin(gimpplugin.plugin):
    '''The main plugin class defines and installs the stitch_panorama function.'''
    version = '0.9.6'
    def query(self):
        gimp.install_procedure("stitch_panorama",
                               "Stitch two images together to make a panorama",
                               "Stitch two images together to make a panorama (ver. " + \
                                stitch_plugin.version+")",
                               "Thomas R. Metcalf",
                               "Thomas R. Metcalf",
                               "2005",
                               "<Toolbox>/Xtns/Utils/Stitch _panorama",
                               "RGB*, GRAY*",EXTENSION,
                               [(PDB_INT32, "run-mode", "interactive/noninteractive"),
                               ],
                               [])

    # stitch_panorama is the main routine where all the work is done.

    def stitch_panorama(self, mode, image_list=None, control_points=None):
        '''Stitch together two images into a panorama.

        First get a set of "control points" which define matching
        locations in the two images.  Then use these control points to
        balance the color and warp the images into a third, panoramic
        image.'''

        if not abort:
            if not image_list: image_list = gimp.image_list()
            # Select which image is the reference and which is transformed.
            image_list=select_images(image_list,mode)
            if check_image_list_ok(image_list,mode):
                image_list[0].disable_undo()
                image_list[1].disable_undo()
                # fire up the user interface which does all the work.
                panorama = stitch_control_panel(control_points,image_list,mode)
                # clean up a bit
                for img in image_list:
                    if img:
                        img.clean_all()
                        img.enable_undo()
                        update_image_layers(img)  # is this necessary?
                gimp.pdb.gimp_displays_flush()
                return panorama

# Pau.

#------------ SUPPORTING CLASS DEFINITIONS

class control_point(object):
    '''Each control point gives matching locations in two images.'''
    def __init__(self,x1,y1,x2,y2,correlation=None,colorbalance=True):
        self.xy = (float(x1),float(y1),float(x2),float(y2))
        self.correlation = correlation
        self.colorbalance = colorbalance
    def x1(self): return self.xy[0]
    def y1(self): return self.xy[1]
    def x2(self): return self.xy[2]
    def y2(self): return self.xy[3]
    def cb(self):
        try:
            colorbalance = self.colorbalance
        except AttributeError:
            colorbalance = True
        return colorbalance
    def invert(self):
        try:
            colorbalance = self.colorbalance
        except AttributeError:
            colorbalance = True
        return control_point(self.x2(),self.y2(),self.x1(),self.y1(),
                                           self.correlation,colorbalance)

minradius = 20.0  # min radius for color averaging

class stitchable(object):
    '''Two images and their control points for stitching.'''
    def __init__(self,mode,rimage,timage,control_points=None):
        self.mode = mode                       # Mode: interactive/noninteractive
        self.rimage = rimage                   # the reference image object
        self.timage = timage                   # the transformed image object
        self.cimage = None                     # temporary image for correlation
        self.dimage = None                     # temporary image for undistorted image
        self.rimglayer = None                  # main image layer in reference image
        self.timglayer = None                  # main image layer in transformed image
        self.rcplayer = None                   # the reference control point display layer
        self.tcplayer = None                   # the transform control point display layer
        self.control_points = control_points   # the warping control points
        self.panorama = None                   # the resulting panoramic image
        self.rlayer = None                     # the reference layer in self.panorama
        self.tlayer = None                     # the transformed layer in self.panorama
        self.rmask = None                      # the reference layer mask
        self.tmask = None                      # the transformed layer mask
        self.rxy = None                        # x,y of reference corners [x1,y1,x2,y2]
        self.txy = None                        # x,y of transformed corners [x1,y1,x2,y2]
        self.interpolation = INTERPOLATION_CUBIC
        self.supersample = 1
        self.cpcorrelate = True                # correlate control points?
        self.recursion_level = 5
        self.clip_result = 1   # this must be 1 or gimp will crash (segmentation fault)
        self.colorbalance = True               # color balance?
        self.colorradius = minradius           # color radius
        self.blend = True                      # blend edges?
        self.blend_fraction = 0.25             # size of blend along edges (fraction of image size)
        self.rmdistortion = True               # remove distortion?
        self.condition_number = None           # the condition number of the transform
        self.progressbar = None                # the progress bar widget
        self.update()
    def __getitem__(self,index):
        '''Make the stitchable class indexable over the control points.'''
        return self.control_points[index]
    def update(self):
        if self.control_points:
            self.npoints = len(self.control_points)
            rarray,tarray = self.arrays()
            self.transform = compute_transform_matrix(rarray,tarray,self)
            self.errors = compute_control_point_errors(self)
        else:
            self.npoints = 0
            self.transform = None
            self.errors = None
    def set_control_points(self,control_points):
        '''Se the whole control point list.'''
        self.control_points = control_points
        self.update()
    def add_control_point(self,cp):
        '''Add a control point to the control_points list.
           The control_point parameter should be of the control_point
           class.'''
        assert cp.__class__ is control_point, \
               'control_point parameter is not an instance of the control_point class.'
        if self.control_points:
            self.control_points.append(cp)
        else:
            self.control_points = [cp]
        self.update()
    def delete_control_point(self,index):
        '''Delete a control point from the control point list.'''
        if self.control_points:
            self.control_points.pop(index)
            self.update()
    def replace_control_point(self,cp,index):
        '''Replace a control point in the control point list.'''
        if self.control_points:
            if index < len(self.control_points):
                self.control_points[index] = cp
                self.update()
    def move_control_point_up(self,index):
        if self.control_points:
            if index > 0 and index < self.npoints:
                cp1 = self.control_points[index]
                cp2 = self.control_points[index-1]
                self.control_points[index] = cp2
                self.control_points[index-1] = cp1
                self.update()
    def move_control_point_down(self,index):
        if self.control_points:
            if index >=0 and index <self.npoints-1:
                cp1 = self.control_points[index]
                cp2 = self.control_points[index+1]
                self.control_points[index] = cp2
                self.control_points[index+1] = cp1
                self.update()
    def inverse_control_points(self):
        '''Invert the control point list and return the inverse.'''
        inverse = []
        for c in self.control_points:
            inverse.append(c.invert())
        return inverse
    def arrays(self):
        '''Get the reference and transformed control points as lists.'''
        rarray = []
        tarray = []
        for i in range(self.npoints):
            rarray.append([self.control_points[i].x1(),self.control_points[i].y1(),1.0])
            tarray.append([self.control_points[i].x2(),self.control_points[i].y2(),1.0])
        return (rarray,tarray)
    def color(self,control_point,radius=minradius):
        '''Get the color values at a control point in each image.
           The return value is a two-element tuple in which each entry
           is a color tuple.'''
        assert control_point in self.control_points,'Bad control point'
        rnx = self.rimage.width   # the dimensions of the images
        rny = self.rimage.height
        tnx = self.timage.width
        tny = self.timage.height
        # Make sure that the radius is not so large that the
        # average circle extends beyond the edge.
        if radius > control_point.x1():
            radius = max(control_point.x1(),1.0)
        if radius > control_point.y1():
            radius = max(control_point.y1(),1.0)
        if control_point.x1()+radius > rnx-1:
            radius = max(rnx-control_point.x1()-1,1.0)
        if control_point.y1()+radius > rny-1:
            radius = max(rny-control_point.y1()-1,1.0)
        #if __debug__: print 'radius: ',radius,control_point.x1(),control_point.y1(),rnx,rny
        # the scale of the transformed image may be different from the scale of the
        # reference image.  So, the radius should be scaled as well.
        if self.transform:
            (sscale,srotation) = transform2rs(self.transform)
            tradius = max(radius/sscale,1.0)
        else:
            tradius = radius
        # Check size of tradius
        if tradius > control_point.x2():
            tradius = max(control_point.x2(),1.0)
            if self.transform: radius = max(tradius*sscale,1.0)
        if tradius > control_point.y2():
            tradius = max(control_point.y2(),1.0)
            if self.transform: radius = max(tradius*sscale,1.0)
        if control_point.x2()+tradius > tnx-1:
            tradius = max(tnx-control_point.x2()-1,1.0)
            if self.transform: radius = max(tradius*sscale,1.0)
        if control_point.y2()+tradius > tny-1:
            tradius = max(tny-control_point.y2()-1,1.0)
            if self.transform: radius = max(tradius*sscale,1.0)
        #if __debug__: print 'radius: ',tradius,control_point.x2(),control_point.y2(),tnx,tny
        ##if __debug__: print 'color radii are ',radius,tradius
        ##if __debug__:
        ##    print 'using a color radius of ',radius,tradius
        return ( gimp.pdb.gimp_image_pick_color(self.rimage,
                                                self.rimglayer,
                                                control_point.x1(),
                                                control_point.y1(),
                                                0, # use the composite image, ignore the drawable
                                                1,radius),
                 gimp.pdb.gimp_image_pick_color(self.timage,
                                                self.timglayer,
                                                control_point.x2(),
                                                control_point.y2(),
                                                0, # use the composite image, ignore the drawable
                                                1,tradius)
                )
    def cbtest(self,control_point):
        '''Get the color balance flag for a control point.'''
        assert control_point in self.control_points,'Bad control point'
        return control_point.cb()

    def cbtests(self):
        '''Get flag to determine if a control point will be used in the color balancing.'''
        return [self.cbtest(self.control_points[c])
                    for c in range(self.npoints)] # iterates over self.control_points

    def colors(self):
        '''Get the color values at all the control points.'''
        if self.errors:
            return [self.color(self.control_points[c],self.colorradius)
                    for c in range(self.npoints)] # iterates over self.control_points
        else:
            return [self.color(c) for c in self] # iterates over self.control_points

    def brightness(self,control_point,radius=minradius):
        '''Compute the brightness of a control point in each image.
           The return value is a two-element tuple in which the entries
           are the brightness of the two images in the stitchable object.'''
        c = self.color(control_point,radius)
        brightness1 = 0
        brightness2 = 0
        n = 0.0
        for b1,b2 in zip(c[0],c[1]):  # iterate over both image colors simultaneously
            brightness1 += b1
            brightness2 += b2
            n += 1.0
        # the brightness is the mean of the values
        return (int(round(brightness1/n)),int(round(brightness2/n)))
    def brightnesses(self):
        '''Get the brightness values at all the control points.'''
        if self.errors:
            return [self.brightness(self.control_points[c],self.colorradius)
                    for c in range(self.npoints)] # iterates over self.control_points
        else:
            return [self.brightness(c) for c in self] # iterates over self.control_points

    def value(self,control_point,radius=minradius):
        '''Compute the value of a control point in each image.
           The return value is a two-element tuple in which the entries
           are the value of the two images in the stitchable object.'''
        c = self.color(control_point,radius)
        # the value is the max of the color channels
        return ( max(c[0]), max(c[1]) )
    def values(self):
        '''Get the values at all the control points.'''
        if self.errors:
            return [self.value(self.control_points[c],self.colorradius)
                    for c in range(self.npoints)]
        else:
            return [self.value(c) for c in self] # iterates over self.control_points

答案1

在 Windows 上,Gimp 自 2.8 版起就内置了 Python 支持。要检查它是否正常工作,请执行以下操作:

  • 你应该有菜单Filters>Python-fu>Console
  • 它应该打开一个 Python 控制台。
  • 你还应该滤镜>装饰>雾(2.10)或文件管理器>渲染>云>雾(2.8,根据记忆)。

另一方面,您的过滤器似乎非常老旧(2005 年,因此与 Gimp 2.2 是同一时期的)。上面的代码不完整,完整代码超过 3800 行(检索到的这里)。

此完整代码已正确注册,但 Gimp 不再允许菜单位置,因此实际菜单位置是滤镜>实用工具>拼接全景图

该插件从 Gimp 2.10 开始,但我没有进一步测试。这个插件在 2005 年可能很有用,但现在全景拼接用胡金

相关内容