Saya tahu ini bukan tempat yang ideal untuk pertanyaan lingkup ini, tetapi saya tidak yakin di mana lagi untuk menanyakan ini atau bagaimana memecahnya. Saya telah mengerjakan suatu fungsi selama beberapa minggu terakhir, yang berjalan, tetapi agar layak untuk tujuan saya, saya perlu mempercepatnya 200-300x.

Saya memiliki array gambar, di mana semua piksel dengan warna yang sama telah dirata-ratakan dan disetel ke nilai rata-rata itu. Kemudian saya memiliki larik 2D dengan tinggi dan lebar yang sama, yang memberi label pada setiap fitur gambar yang unik dan tidak bersebelahan.

Dengan menggunakan ini saya perlu menilai ukuran setiap fitur dan tingkat kontrasnya dengan masing-masing tetangganya. Nilai-nilai ini digunakan dalam sebuah persamaan dan jika output dari persamaan tersebut berada di bawah ambang batas tertentu, fitur tersebut akan digabungkan dengan tetangganya yang paling mirip.

Saya telah mengunggah gambar dan larik label fitur (dicetak dengan numpy.savetext()) ke OneDrive dan tautan terlampir

Kode:

def textureRemover(pix, labeledPix, ratio = 1.0):
    numElements = numpy.amax(labeledPix)
    maxSize = numpy.count_nonzero(labeledPix)
    MAXIMUMCONTRAST = 443.405

    for regionID in range(numElements):        
        start = time.clock()
        regionID += 1
        if regionID not in labeledPix:
            continue

        #print(regionID)
        #print((regionID / numElements) * 100, '%')

        neighborIDs = getNeighbors(labeledPix, regionID)
        if 0 in neighborIDs:
            neighborIDs.remove(0) #remove white value
        regionMask = labeledPix == regionID

        region = pix[regionMask]

        size = numpy.count_nonzero(regionMask)
        contrastMin = (ratio - (size / maxSize)) * MAXIMUMCONTRAST 
        regionMean = region.mean(axis = 0)

        if len(neighborIDs) > 200:
            contrast = numpy.zeros(labeledPix.shape)
            contrast[labeledPix!=0] = numpy.sqrt(numpy.sum((regionMean - pix[labeledPix!=0])**2, axis = -1))

            significantMask = (contrast < contrastMin)
            significantContrasts = list(numpy.unique(contrast[significantMask]))

            significantNeighbors = {}
            for significantContrast in significantContrasts:
                minContrast = min(significantContrasts)
                if labeledPix[contrast == minContrast][0] in neighborIDs:
                    significantNeighbors[minContrast] = labeledPix[contrast == minContrast][0]
                else:
                    significantContrasts.pop(significantContrasts.index(minContrast))

        else:
            significantNeighbors = {}
            for neighborID in neighborIDs:
                neighborMask = labeledPix == neighborID
                neighbor = pix[neighborMask]
                neighborMean = neighbor.mean(axis = 0)
                contrast = numpy.sqrt(numpy.sum((regionMean - neighborMean)**2, axis = -1))
                if contrast < contrastMin:
                    significantNeighbors[contrast] = neighborID

        if significantNeighbors:
            contrasts = significantNeighbors.keys()            
            minContrast = min(contrasts)

            minNeighbor = significantNeighbors[minContrast]
            neighborMask = labeledPix == minNeighbor
            neighborSize = numpy.count_nonzero(neighborMask)

            if neighborSize <= size:
                labeledPix[neighborMask] = regionID
                pix[neighborMask] = regionMean

            else:
                labeledPix[regionMask] = minNeighbor
                pix[regionMask] = pix[neighborMask].mean(axis = 0)

        print(time.clock() - start)
    return pix

pix

berlabelPix

Saya tahu saya meminta banyak bantuan, tetapi saya telah terjebak dalam hal ini selama beberapa minggu dan tidak yakin apa lagi yang bisa saya lakukan. Bantuan apa pun akan sangat dihargai!

0
asheets 4 Januari 2018, 00:10

1 menjawab

Jawaban Terbaik

Ini adalah versi yang dioptimalkan dari sebagian besar logika Anda (saya meremehkan jumlah pekerjaan yang akan...). Saya melewatkan cabang >200 dan menggunakan data palsu karena saya tidak dapat mengakses tautan Anda. Ketika saya mematikan cabang >200 Anda, kode Anda dan kode saya tampaknya memberikan hasil yang sama tetapi milik saya sedikit lebih cepat pada contoh palsu.

Contoh keluaran:

original
26.056154000000003
optimized
0.763613000000003
equal
True

Kode:

import numpy as np
from numpy.lib.stride_tricks import as_strided

def mockdata(m, n, k):
    colors = np.random.random((m, n, 3))
    i, j = np.ogrid[:m, :n]
    labels = np.round(k*k * (np.sin(0.05 * i) + np.sin(0.05 * j)**2)).astype(int) % k
    return colors, labels

DIAG_NEIGHBORS = True
MAXIMUMCONTRAST = 443.405

def textureRemover2(pix, labeledPix, ratio=1.0):
    start = time.clock()
    pix, labeledPix = pix.copy(), labeledPix.copy()
    pixf, labeledPixf = pix.reshape(-1, 3), labeledPix.ravel()
    m, n = labeledPix.shape
    s, t = labeledPix.strides
    # find all sizes in O(n)
    sizes = np.bincount(labeledPixf)
    n_ids = len(sizes)
    # make index for quick access to labeled areas
    lblidx = np.split(np.argsort(labeledPixf), np.cumsum(sizes[:-1]))
    lblidx[0] = None
    # find all mean colors in O(n)
    regionMeans = np.transpose([np.bincount(labeledPix.ravel(), px)
                                / np.maximum(sizes, 1)
                                for px in pix.reshape(-1, 3).T])
    # find all neighbors in O(n)
    horz = set(frozenset(p) for bl in as_strided(labeledPix, (m,n-1,2), (s,t,t))
               for p in bl)
    vert = set(frozenset(p) for bl in as_strided(labeledPix, (m-1,n,2), (s,t,s))
               for p in bl)
    nb = horz|vert
    if DIAG_NEIGHBORS:
        dwnrgt = set(frozenset(p) for bl in as_strided(
            labeledPix, (m-1,n-1,2), (s,t,s+t)) for p in bl)
        dwnlft = set(frozenset(p) for bl in as_strided(
            labeledPix[::-1], (m-1,n-1,2), (-s,t,t-s)) for p in bl)
        nb = nb|dwnrgt|dwnlft
    nb = {p for p in nb if len(p) == 2 and not 0 in p}
    nb_dict = {}
    for a, b in nb:
        nb_dict.setdefault(a, set()).add(b)
        nb_dict.setdefault(b, set()).add(a)

    maxSize = labeledPix.size - sizes[0]

    for id_ in range(1, n_ids):
        nbs = list(nb_dict.get(id_, set()))
        if not nbs:
            continue
        d = regionMeans[id_] - regionMeans[nbs]
        d = np.einsum('ij,ij->i', d, d)
        mnd = np.argmin(d)
        if d[mnd] < ((ratio - sizes[id_]/maxSize) * MAXIMUMCONTRAST)**2:
            mn = nbs[mnd]
            lrg, sml = (id_, mn) if sizes[id_] >= sizes[mn] else (mn, id_)
            sizes[lrg], sizes[sml] = sizes[lrg] + sizes[sml], 0
            for nb in nb_dict[sml]:
                nb_dict[nb].remove(sml)
                nb_dict[nb].add(lrg)
            nb_dict[lrg].update(nb_dict[sml])
            nb_dict[lrg].remove(lrg)
            nb_dict[sml] = set()
            pixf[lblidx[sml]] = regionMeans[lrg]
            labeledPixf[lblidx[sml]] = lrg
            lblidx[lrg], lblidx[sml] = np.r_[lblidx[lrg],lblidx[sml]], None
    print(time.clock() - start)
    return pix

from scipy.ndimage.morphology import binary_dilation
import time

STRUCTEL = np.ones((3,3), int) if DIAG_NEIGHBORS else np.array([[0,1,0],[1,1,1],[0,1,0]], int)

def getNeighbors(labeledPix, regionID):
    nb = set(labeledPix[binary_dilation(labeledPix == regionID, structure=STRUCTEL)])
    nb.remove(regionID)
    return sorted(nb)

numpy = np

def textureRemover(pix, labeledPix, ratio = 1.0):
    pix, labeledPix = pix.copy(), labeledPix.copy()
    numElements = numpy.amax(labeledPix)
    maxSize = numpy.count_nonzero(labeledPix)
    MAXIMUMCONTRAST = 443.405

    start = time.clock()
    for regionID in range(numElements):        
        regionID += 1
        if regionID not in labeledPix:
            continue

        #print(regionID)
        #print((regionID / numElements) * 100, '%')

        neighborIDs = getNeighbors(labeledPix, regionID)
        if 0 in neighborIDs:
            neighborIDs.remove(0) #remove white value
        regionMask = labeledPix == regionID

        region = pix[regionMask]

        size = numpy.count_nonzero(regionMask)
        contrastMin = (ratio - (size / maxSize)) * MAXIMUMCONTRAST 
        regionMean = region.mean(axis = 0)

        if len(neighborIDs) > 20000:
            contrast = numpy.zeros(labeledPix.shape)
            contrast[labeledPix!=0] = numpy.sqrt(numpy.sum((regionMean - pix[labeledPix!=0])**2, axis = -1))

            significantMask = (contrast < contrastMin)
            significantContrasts = list(numpy.unique(contrast[significantMask]))

            significantNeighbors = {}
            for significantContrast in significantContrasts:
                minContrast = min(significantContrasts)
                if labeledPix[contrast == minContrast][0] in neighborIDs:
                    significantNeighbors[minContrast] = labeledPix[contrast == minContrast][0]
                else:
                    significantContrasts.pop(significantContrasts.index(minContrast))

        else:
            significantNeighbors = {}
            for neighborID in neighborIDs:
                neighborMask = labeledPix == neighborID
                neighbor = pix[neighborMask]
                neighborMean = neighbor.mean(axis = 0)
                contrast = numpy.sqrt(numpy.sum((regionMean - neighborMean)**2, axis = -1))
                if contrast < contrastMin:
                    significantNeighbors[contrast] = neighborID

        if significantNeighbors:
            contrasts = significantNeighbors.keys()            
            minContrast = min(contrasts)

            minNeighbor = significantNeighbors[minContrast]
            neighborMask = labeledPix == minNeighbor
            neighborSize = numpy.count_nonzero(neighborMask)

            if neighborSize <= size:
                labeledPix[neighborMask] = regionID
                pix[neighborMask] = regionMean

            else:
                labeledPix[regionMask] = minNeighbor
                pix[regionMask] = pix[neighborMask].mean(axis = 0)

    print(time.clock() - start)
    return pix

data = mockdata(200, 200, 1000)
print('original')
res0 = textureRemover(*data)
print('optimized')
res2 = textureRemover2(*data)
print('equal')
print(np.allclose(res0, res2))
1
Paul Panzer 5 Januari 2018, 15:59