Почему аргумент по умолчанию не может быть указан для явной специализации шаблона?

У меня есть подход, который я считаю интересным и немного отличным от остальных. Основное отличие моего подхода по сравнению с некоторыми другими заключается в том, как выполняется этап сегментации изображения - я использовал алгоритм кластеризации DBSCAN из Python's scikit-learn; он оптимизирован для поиска несколько аморфных форм, которые могут не обязательно иметь единый четкий центроид.

На верхнем уровне мой подход довольно прост и может быть разбит на 3 этапа. Сначала я применяю порог (или фактически, логическое «или» двух отдельных и разных порогов). Как и во многих других ответах, я предположил, что рождественская елка будет одним из самых ярких объектов в сцене, поэтому первый порог - это просто простой монохромный тест яркости; любые пиксели со значениями выше 220 по шкале 0-255 (где черный равен 0, а белый - 255) сохраняются в двоичном черно-белом изображении. Второй порог пытается найти красные и желтые огни, которые особенно заметны на деревьях в верхнем левом и нижнем правом углу шести изображений и хорошо выделяются на сине-зеленом фоне, который преобладает на большинстве фотографий. Я преобразовываю изображение rgb в пространство hsv и требую, чтобы оттенок был меньше 0,2 по шкале 0,0-1,0 (примерно соответствует границе между желтым и зеленым) или больше 0,95 (соответствует границе между фиолетовым и красным) и дополнительно мне требуются яркие, насыщенные цвета: насыщенность и значение должны быть выше 0,7. Результаты двух пороговых процедур логически «или» объединены, и результирующая матрица черно-белых двоичных изображений показана ниже:

Christmas trees, after thresholding on HSV as well as monochrome brightness

Вы можете ясно видеть, что каждое изображение имеет один большой кластер пикселей, приблизительно соответствующий местоположению каждого дерева, плюс несколько изображений также имеют некоторые другие небольшие кластеры, соответствующие либо огням в окнах некоторых зданий, либо фоновая сцена на горизонте. Следующим шагом будет заставить компьютер распознавать, что это отдельные кластеры, и правильно маркировать каждый пиксель идентификационным номером членства в кластере.

Для этой задачи я выбрал DBSCAN . Существует довольно хорошее визуальное сравнение того, как DBSCAN обычно ведет себя по сравнению с другими алгоритмами кластеризации, доступно здесь здесь . Как я уже говорил ранее, это хорошо с аморфными формами. Выходные данные DBSCAN с каждым кластером, нанесенным на график в другом цвете, показаны здесь: , Во-первых, DBSCAN требует, чтобы пользователь установил параметр «близости», чтобы регулировать его поведение, которое эффективно контролирует, как должна быть разделена пара точек, чтобы алгоритм объявлял новый отдельный кластер, а не агломерировал контрольную точку на уже существующий кластер. Я установил это значение в 0,04 раза больше размера по диагонали каждого изображения. Поскольку размер изображения варьируется от примерно VGA до примерно HD 1080, этот тип определения относительно масштаба имеет решающее значение.

Еще один момент, который стоит отметить, заключается в том, что алгоритм DBSCAN, реализованный в scikit-learn, имеет ограничения памяти, которые довольно сложны для некоторых больших изображений в этом примере. Поэтому для нескольких более крупных изображений мне фактически пришлось «прореживать» (т.е. сохранять только каждый 3-й или 4-й пиксель и отбрасывать остальные) каждый кластер, чтобы оставаться в пределах этого предела. В результате этого процесса отбраковки оставшиеся отдельные разреженные пиксели трудно увидеть на некоторых больших изображениях. Поэтому, только для целей отображения, пиксели с цветовой кодировкой в ​​приведенных выше изображениях были эффективно "немного расширены", чтобы они лучше выделялись. Это чисто косметическая операция ради повествования; хотя в моем коде есть упоминания об этом расширении, будьте уверены, что он не имеет никакого отношения к каким-либо вычислениям, которые действительно имеют значение.

После того, как кластеры идентифицированы и помечены, третий и последний шаг становится легким: я просто беру самый большой кластер в каждом изображении (в этом случае я решил измерить «размер» с точки зрения общего количества пикселей-членов, хотя можно было бы так же легко вместо этого использовать некоторый тип метрики, который измеряет физическую протяженность) и вычислить выпуклую оболочку для этого кластера. Затем выпуклая оболочка становится границей дерева. Шесть выпуклых оболочек, вычисленных с помощью этого метода, показаны ниже красным цветом:

Christmas trees with their calculated borders

Исходный код написан для Python 2.7.6 и зависит от numpy , scipy , matplotlib и scikit-learn . Я разделил это на две части. Первая часть отвечает за фактическую обработку изображения:

from PIL import Image
import numpy as np
import scipy as sp
import matplotlib.colors as colors
from sklearn.cluster import DBSCAN
from math import ceil, sqrt

"""
Inputs:

    rgbimg:         [M,N,3] numpy array containing (uint, 0-255) color image

    hueleftthr:     Scalar constant to select maximum allowed hue in the
                    yellow-green region

    huerightthr:    Scalar constant to select minimum allowed hue in the
                    blue-purple region

    satthr:         Scalar constant to select minimum allowed saturation

    valthr:         Scalar constant to select minimum allowed value

    monothr:        Scalar constant to select minimum allowed monochrome
                    brightness

    maxpoints:      Scalar constant maximum number of pixels to forward to
                    the DBSCAN clustering algorithm

    proxthresh:     Proximity threshold to use for DBSCAN, as a fraction of
                    the diagonal size of the image

Outputs:

    borderseg:      [K,2,2] Nested list containing K pairs of x- and y- pixel
                    values for drawing the tree border

    X:              [P,2] List of pixels that passed the threshold step

    labels:         [Q,2] List of cluster labels for points in Xslice (see
                    below)

    Xslice:         [Q,2] Reduced list of pixels to be passed to DBSCAN

"""

def findtree(rgbimg, hueleftthr=0.2, huerightthr=0.95, satthr=0.7, 
             valthr=0.7, monothr=220, maxpoints=5000, proxthresh=0.04):

    # Convert rgb image to monochrome for
    gryimg = np.asarray(Image.fromarray(rgbimg).convert('L'))
    # Convert rgb image (uint, 0-255) to hsv (float, 0.0-1.0)
    hsvimg = colors.rgb_to_hsv(rgbimg.astype(float)/255)

    # Initialize binary thresholded image
    binimg = np.zeros((rgbimg.shape[0], rgbimg.shape[1]))
    # Find pixels with hue<0.2 or hue>0.95 (red or yellow) and saturation/value
    # both greater than 0.7 (saturated and bright)--tends to coincide with
    # ornamental lights on trees in some of the images
    boolidx = np.logical_and(
                np.logical_and(
                  np.logical_or((hsvimg[:,:,0] < hueleftthr),
                                (hsvimg[:,:,0] > huerightthr)),
                                (hsvimg[:,:,1] > satthr)),
                                (hsvimg[:,:,2] > valthr))
    # Find pixels that meet hsv criterion
    binimg[np.where(boolidx)] = 255
    # Add pixels that meet grayscale brightness criterion
    binimg[np.where(gryimg > monothr)] = 255

    # Prepare thresholded points for DBSCAN clustering algorithm
    X = np.transpose(np.where(binimg == 255))
    Xslice = X
    nsample = len(Xslice)
    if nsample > maxpoints:
        # Make sure number of points does not exceed DBSCAN maximum capacity
        Xslice = X[range(0,nsample,int(ceil(float(nsample)/maxpoints)))]

    # Translate DBSCAN proximity threshold to units of pixels and run DBSCAN
    pixproxthr = proxthresh * sqrt(binimg.shape[0]**2 + binimg.shape[1]**2)
    db = DBSCAN(eps=pixproxthr, min_samples=10).fit(Xslice)
    labels = db.labels_.astype(int)

    # Find the largest cluster (i.e., with most points) and obtain convex hull   
    unique_labels = set(labels)
    maxclustpt = 0
    for k in unique_labels:
        class_members = [index[0] for index in np.argwhere(labels == k)]
        if len(class_members) > maxclustpt:
            points = Xslice[class_members]
            hull = sp.spatial.ConvexHull(points)
            maxclustpt = len(class_members)
            borderseg = [[points[simplex,0], points[simplex,1]] for simplex
                          in hull.simplices]

    return borderseg, X, labels, Xslice

, а вторая часть представляет собой сценарий пользовательского уровня, который вызывает первый файл и генерирует все приведенные выше графики:

#!/usr/bin/env python

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from findtree import findtree

# Image files to process
fname = ['nmzwj.png', 'aVZhC.png', '2K9EF.png',
         'YowlH.png', '2y4o5.png', 'FWhSP.png']

# Initialize figures
fgsz = (16,7)        
figthresh = plt.figure(figsize=fgsz, facecolor='w')
figclust  = plt.figure(figsize=fgsz, facecolor='w')
figcltwo  = plt.figure(figsize=fgsz, facecolor='w')
figborder = plt.figure(figsize=fgsz, facecolor='w')
figthresh.canvas.set_window_title('Thresholded HSV and Monochrome Brightness')
figclust.canvas.set_window_title('DBSCAN Clusters (Raw Pixel Output)')
figcltwo.canvas.set_window_title('DBSCAN Clusters (Slightly Dilated for Display)')
figborder.canvas.set_window_title('Trees with Borders')

for ii, name in zip(range(len(fname)), fname):
    # Open the file and convert to rgb image
    rgbimg = np.asarray(Image.open(name))

    # Get the tree borders as well as a bunch of other intermediate values
    # that will be used to illustrate how the algorithm works
    borderseg, X, labels, Xslice = findtree(rgbimg)

    # Display thresholded images
    axthresh = figthresh.add_subplot(2,3,ii+1)
    axthresh.set_xticks([])
    axthresh.set_yticks([])
    binimg = np.zeros((rgbimg.shape[0], rgbimg.shape[1]))
    for v, h in X:
        binimg[v,h] = 255
    axthresh.imshow(binimg, interpolation='nearest', cmap='Greys')

    # Display color-coded clusters
    axclust = figclust.add_subplot(2,3,ii+1) # Raw version
    axclust.set_xticks([])
    axclust.set_yticks([])
    axcltwo = figcltwo.add_subplot(2,3,ii+1) # Dilated slightly for display only
    axcltwo.set_xticks([])
    axcltwo.set_yticks([])
    axcltwo.imshow(binimg, interpolation='nearest', cmap='Greys')
    clustimg = np.ones(rgbimg.shape)    
    unique_labels = set(labels)
    # Generate a unique color for each cluster 
    plcol = cm.rainbow_r(np.linspace(0, 1, len(unique_labels)))
    for lbl, pix in zip(labels, Xslice):
        for col, unqlbl in zip(plcol, unique_labels):
            if lbl == unqlbl:
                # Cluster label of -1 indicates no cluster membership;
                # override default color with black
                if lbl == -1:
                    col = [0.0, 0.0, 0.0, 1.0]
                # Raw version
                for ij in range(3):
                    clustimg[pix[0],pix[1],ij] = col[ij]
                # Dilated just for display
                axcltwo.plot(pix[1], pix[0], 'o', markerfacecolor=col, 
                    markersize=1, markeredgecolor=col)
    axclust.imshow(clustimg)
    axcltwo.set_xlim(0, binimg.shape[1]-1)
    axcltwo.set_ylim(binimg.shape[0], -1)

    # Plot original images with read borders around the trees
    axborder = figborder.add_subplot(2,3,ii+1)
    axborder.set_axis_off()
    axborder.imshow(rgbimg, interpolation='nearest')
    for vseg, hseg in borderseg:
        axborder.plot(hseg, vseg, 'r-', lw=3)
    axborder.set_xlim(0, binimg.shape[1]-1)
    axborder.set_ylim(binimg.shape[0], -1)

plt.show()

24
задан Thomson 29 October 2010 в 08:28
поделиться

1 ответ

C ++ 98 §12.7 / 21 «Аргументы функции по умолчанию не должны указываться в ... явной специализации шаблона функции».

Что касается обоснования, я думаю, что это связано с тем, что вызов всегда разрешается по основному шаблону. Вызов, в котором пропущен аргумент, требуемый основным шаблоном, не может быть решен без изменения правил поиска.

15
ответ дан 28 November 2019 в 23:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: