2012-06-08 19 views
11

Ho una tabella MySQL con migliaia di punti dati memorizzati in 3 colonne R, G, B. come posso trovare quale punto dati è più vicino a un dato punto (a, b, c) usando la distanza euclidea?Qual è il modo più efficace per trovare la distanza euclidea in 3d usando mysql?

Sto salvando i valori RGB dei colori separatamente in una tabella, quindi i valori sono limitati a 0-255 in ogni colonna. Quello che sto cercando di fare è trovare la corrispondenza cromatica più vicina trovando il colore con la più piccola distanza euclidea.

Potrei ovviamente percorrere tutti i punti del tavolo per calcolare la distanza ma non sarebbe abbastanza efficiente da scalare. Qualche idea?

+3

Se in realtà stai parlando di ** colori **, probabilmente [non dovresti usare la distanza euclidea nello spazio RGB] (http://stackoverflow.com/questions/1313/followup-finding-an-accurate- distanza-tra-colori) – AakashM

risposta

2
  1. Dal momento che si sta cercando la distanza minima e non esatta distanza è possibile ignorare la radice quadrata. Penso che lo Squared Euclidean Distance si applichi qui.
  2. Hai detto che i valori sono compresi tra 0-255, quindi puoi creare una tabella di ricerca indicizzata con 255 valori.

Ecco cosa sto pensando in termini di SQL.r0, g0 e b0 rappresentano il colore di destinazione. La tabella Vector manterrebbe i valori quadrati sopra menzionati in # 2. Questa soluzione visiterebbe tutti i record ma il set di risultati può essere impostato su 1 ordinando e selezionando solo la prima riga.

select 
    c.r, c.g, c.b, 
    mR.dist + mG.dist + mB.dist as squared_dist 
from 
    colors c, 
    vector mR, 
    vector mG, 
    vector mB 
where 
    c.r-r0 = mR.point and 
    c.g-g0 = mG.point and 
    c.b-b0 = mB.point 
group by 
    c.r, c.g, c.b 
+0

Devo dire che penso che la tua soluzione non sia corretta, user845279 ... Se aggiungi i 3 valori, troverai, a causa delle leggi commutative della matematica (del plus/addizione), che 10 + 50 + 80 = 140, ma lo è anche 10 + 120 + 10, e quindi anche 1 + 138 + 1, o, 80 + 50 + 10. Se almeno usi la formula della distanza con la radice quadrata della somma dei componenti ogni quadrato , quindi otterrai una formula migliore per la distanza nello spazio tridimensionale che comprende il cubo XYZ (RGB) che varia per ogni dimensione tra 0 e 255 ... –

0

Credo ci siano due opzioni.

Si deve o come si dice iterare su tutto il set e confrontare e confrontare con un massimo impostato inizialmente su un numero incredibilmente basso come -1. Funziona in tempo lineare, n volte (dal momento che stai confrontando solo 1 punto con ogni punto dell'insieme, questo scala in modo lineare).

Sto ancora pensando ad un'altra opzione ... qualcosa sulla falsariga di fare una prima ricerca di ampiezza lontano dal punto di input fino a quando un punto si trova nell'insieme nel punto cercato, ma questo richiede un po 'più di riflessione (Immagino che lo spazio 3D dovrebbe essere abbastanza popolato perché questo sia in media più efficiente).

1

Il primo livello di ottimizzazione che vedo che si può fare sarebbe quadrato la distanza a cui si desidera limitare la query in modo che non sia necessario eseguire la radice quadrata per ogni riga. Il secondo livello di ottimizzazione che incoraggerei sarebbe una pre-elaborazione per alleggerire la necessità di quadratura estranea per ogni query (che potrebbe creare un po 'di tempo extra per le grandi tabelle di RGB). Dovresti fare un po 'di benchmarking per vedere, ma sostituendo i valori di a, b, c edd e poi eseguendo la query, potresti alleviare lo stress da MySQL.

Latex

nota che la differenza di prestazioni tra le ultime due righe può essere trascurabile. Dovrai utilizzare le query di prova sul tuo sistema per determinare quale sia più veloce.

Ho appena riletto e ho notato che stai ordinando per distanza. In tal caso, la d dovrebbe essere rimossa, tutto dovrebbe essere spostato su un lato. È ancora possibile collegare le costanti per evitare un'ulteriore elaborazione su MySQL.

0

Se si attraversano tutti i punti e si calcola la distanza, non utilizzare la funzione radice quadrata, non è necessario. La più piccola somma di quadrati sarà sufficiente.

Questo è il problem che si sta tentando di risolvere. (Caso planare, selezionare tutti i punti ordinati da un asse x, yo Z. Quindi utilizzare PHP per elaborarli)

MySQL ha anche un Spatial Database che può avere questo come funzione. Non sono comunque positivo.

+0

Stavo guardando anche quella pagina di wikipedia sul problema del paio di punti più vicino, ma questo è per confrontare tutti i punti con tutti gli altri punti per trovare la distanza minima tra ogni coppia. Per non parlare, credo che sarebbe necessario ordinare in base a due delle tre dimensioni e lo smistamento danneggerebbe l'efficienza. Sembra anche che il Database spaziale si occupi solo di 2 punti dimensionali sebbene non l'abbia usato. – shaunhusain

2

penso che le osservazioni di cui sopra sono tutte vere, ma sono - a mio modesto parere - non rispondere alla domanda originale. (Correggimi se sbaglio). Quindi, lasciatemi aggiungere i miei 50 cent:

Stai chiedendo un'istruzione select, che, data la tua tabella è chiamata 'colors', e date le tue colonne sono chiamate r, geb, sono numeri interi 0 ..255, e siete alla ricerca per il valore, nella tabella, più vicina a un dato valore, consente di dire: rr, gg, bb, quindi oserei provare il seguente:

select min(sqrt((rr-r)*(rr-r)+(gg-g)*(gg-g)+(bb-b)*(bb-b))) from colors; 

Ora, questa risposta è dato con un sacco di avvertimenti, in quanto non sono sicuro di aver risposto correttamente alla domanda, quindi conferma se è giusto o correggimi in modo da poterti aiutare.

+0

Hm? Eh? Stavo mettendo alcune stelle per moltiplicare, invece di diventare stelle, (asterisco), ha reso il codice in corsivo, ha ha ha ... Quindi, tra la parentesi di (rr-r) (rr-r) ci doveva essere una stella. Allo stesso modo con (gg-g) (gg-g), ha ha ha ... Questo è uno stile di formattazione usato dal latex negli anni '80 sui mainframe !!! (sì, sono un vecchio ragazzo) ... –

+0

grazie per aver risposto alla domanda in SQL, che è quello che stavo cercando di fare - anche se mi chiedo se questo sarebbe orribilmente efficiente – soulkphp

Problemi correlati