Играем в идеальный тетрис: как выровнять и масштабировать две кривые с помощью масштабирования и перевода?

Учитывая параметры масштабирования по оси (-ям) y и перемещения по оси x (t), как масштабировать и выровнять две кривые, которые не совпадают, когда целью является максимизация суперпозиции кривых (не минимизация расстояния)?

Как указывает @DWin, это может быть переименовано в «Как идеально играть в тетрис с R», хотя у него есть приложения, выходящие далеко за рамки победы в игре в тетрис.

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

Дана кривая 1

curve1<-data.frame(x=c(1,1,2,2,3),
                   y=c(9,6,6,3,3))

with(curve1, plot(x=x, y=y, type="l", xlim=c(0,10), ylim=c(0,10)))

введите описание изображения здесь

и кривая 2

curve2<-data.frame(x=c(4,5,5,6,6,7),
                   y=c(2,2,1,1,2,3))

with(curve2, plot(x=x, y=y, type="l", xlim=c(0,10), ylim=c(0,10)))

кривая 2

Я хочу найти s и t, которые максимизируют суперпозицию между двумя кривыми.

В идеале метод должен быть в R с использованием optim.

В этом примере t = 3 и s = 1/3, так что

t=3
s=1/3

with(curve2, plot(x=x, y=y, type="l", xlim=c(0,10), ylim=c(0,10)))

with(curve1, lines(x=x+t, y=y*s, col="red"))

введите описание изображения здесь

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

Trails I have been exploring:

  • minimize area between curves
  • algorithm for superposing two curves
  • shape analysis using the shapes package
  • Iterative closest point (ICP) if someone has implemented it in R or can port one of the C implementations

    Бонусные баллы за метод, использующий максимальное правдоподобие (при нормальном распределении ошибки).


  • person Etienne Low-Décarie    schedule 31.05.2012    source источник
    comment
    Хм. Интересная проблема. Одна вещь, которую необходимо учитывать, заключается в том, что, вероятно, нужно что-то сделать, чтобы избежать патологических результатов. В частности, локальный оптимум, скорее всего, будет в том случае, если вы сильно увеличиваете одну фигуру и, таким образом, помещаете все в часть прямой линии ...   -  person Fhnuzoag    schedule 07.06.2012
    comment
    Есть идеи, как это сделать, но есть быстрый вопрос. Предположим, что это две фигуры в стиле калькулятора 5 (т.е. пять равных горизонтальных / вертикальных сегментов линии, соединенных вместе, чтобы образовать фигуру 5 - конечно, вы понимаете, что я имею в виду), и сегмент вертикальной линии (также известный как калькулятор в стиле 1). Здесь я хочу убедиться, что вы считаете лучшим решением решение со 100% перекрытием (т.е. вторая фигура точно перекрывается с одним из вертикальных сегментов первой фигуры). Другими словами, тот факт, что большая часть первой формы не покрыта и довольно далеко от второй формы, не имеет значения, верно?   -  person Tim P    schedule 09.06.2012
    comment
    Итак, мне удалось придумать интересный метод, который обнаруживает точную суперпозицию - но способ определения проблемы, я думаю, вы неизбежно столкнетесь с проблемами с локальными минимумами, от которых вы не хотите отходить. Могу я просто спросить, считаете ли вы вероятным (исходя из решаемой вами проблемы), что фигура 1 целиком может быть наложена на фигуру 2?   -  person Tim P    schedule 09.06.2012
    comment
    @TimP, степень перекрытия между фигурами 1 и 2 произвольная. Иногда первая фигура полностью вписывается в фигуру два, как вы указали.   -  person Etienne Low-Décarie    schedule 11.06.2012


    Ответы (2)


    Это вернет расстояния между точками, когда curve1 масштабируется по оси y с коэффициентом «tfac» и перемещается по оси x на величину «s»:

     as.matrix( dist( rbind(as.matrix(curve2), 
                     ( matrix(c(rep(s, 5), rep(1,5)), ncol=2) +   # x-shift matrix
                                           as.matrix(curve1) ) %*% 
                       matrix(c( 1, 0, 0, tfac),ncol=2) ) ) # the y-scaling matrix
                    )[ 
                               # better not to use 't' as a variable name
          -(1:5), -(6:11)]  # easier to return the relevant distances when in matrix
    

    Это должно быть несложно поместить в функцию, которую нужно минимизировать:

     dfunc <- function(C1, C2, s, tfac) { sum( .... ) }
    

    Я не совсем уверен, что это вернет ожидаемый результат, поскольку целевая функция, которую вы подразумеваете, может не быть суммой расстояний. Возможно, вам придется обратиться к методам целочисленного программирования. Представление задач Optimization CRAN было бы хорошим местом для поиска этих методов в R. Я полагаю, что альтернативой, если возникает эта проблема, могло бы быть округление значения «s» и масштабирование только до ближайшей степени 2.

    dfunc <- function(param, D1=curve1, D2=curve2) { 
               sum( as.matrix(dist( 
                       rbind(as.matrix(D2), 
                             ( matrix(c(rep(param[1], 5), rep(1,5)), ncol=2) + 
                               as.matrix(D1) ) %*% 
                       matrix(c(1,0,0,param[2]),ncol=2) ) ) )[-(1:5), -(6:11)])}
    optim(c(1,1), dfunc)
    #$par
    $[1] 3.3733977 0.2243866
    # trimmed output
    

    Используя эти значения, получается следующая суперпозиция: Суперпозиция с использованием вышеуказанных значений

    Поэтому я мог бы попробовать s = 3, tfac = 0,25. (Оглядываясь назад, я вижу, что поменял роли t и s с того, о чем вы просили. Извините.)

    person IRTFM    schedule 31.05.2012
    comment
    Интересное усилие, спасибо! Однако кажется, что это более сложный вопрос, чем минимизация расстояния, потому что регионы, которые могут иметь консенсус, должны иметь более высокий вес, чем регионы, которые не могут быть наложены друг на друга. - person Etienne Low-Décarie; 31.05.2012
    comment
    Мое предположение на этот счет было сделано еще до того, как я получил этот числовой результат. Попытки минимизировать на основе площади между кривыми также можно попробовать, но я также вижу двусмысленность в этой спецификации проблемы. Я не знаю пакета для игры в тетрис для Р. - person IRTFM; 31.05.2012

    Хорошо, вот попытка решения.

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

    Нет никаких гарантий, что это сработает для более сложных кривых и преобразований, но, по крайней мере, это идея.

     curve2<-data.frame(x=c(4,5,5,6,6,7),
                        y=c(2,2,1,1,2,3))
     fillin <- function(ax, ay, bx, by, scaling= 10, steps= 100) floor(cbind(seq(from = ax, to = bx, len = steps), seq(from = ay, to = by, len = steps)) * scaling)
     Bmat <- matrix(0, 100, 100)
     for (i in 2:nrow(curve2)){
     Bmat[fillin (curve2[i-1,1], curve2[i-1,2], curve2[i,1], curve2[i,2])] =1
     }
     Bmat.orig = Bmat
    
     Bmat = Bmat.orig
     #construct utility function based on 
     #manhattan distances to closest point?
     shift = function(mat, offset){
     mat0 = array(0, dim = dim(mat)+2)
     mat0[1:nrow(mat) +1+ offset[1] , 1:ncol(mat) + 1+offset[2]] = mat
     return(mat0[1:nrow(mat) + 1, 1:ncol(mat) + 1])
     }
    
     for (i in 1:100){
     Bm = (Bmat != 0)
     Btmp1 = shift(Bm, c(1,0))
     Btmp2 = shift(Bm, c(-1,0))
     Btmp3 = shift(Bm, c(0,1))
     Btmp4 = shift(Bm, c(0,-1))
    
     Bmat = Bmat + pmax(Bm ,Btmp1, Btmp2, Btmp3, Btmp4)/i
     }
    
     Bmat2 = replace(Bmat, Bmat == max(Bmat), max(Bmat) + 10)
    
     #construct and compare rasterised versions
     getcurve = function(trans = c(0,1),  curve=data.frame(x=c(1,1,2,2,3) ,
                        y=c(9,6,6,3,3) ), Bmat = Bmat2){
     Amat = array(0, dim = dim(Bmat))
     curve[,1] = curve[,1] + trans[1]
     curve[,2] = curve[,2] * trans[2]
     for (i in 2:nrow(curve)){
     fillin (curve[i-1,1], curve[i-1,2], curve[i,1], curve[i,2]) -> ind
     if (min(ind) < 1 || max(ind) > nrow(Bmat)) return( array(-1, dim= dim(Bmat)))
     Amat[ind] =1
     }
     Amat = (Amat - mean(Amat))/sd(as.vector(Amat))
     Amat
     }
     compcurve = function(trans = c(0,1), curve=data.frame(x=c(1,1,2,2,3) ,
                        y=c(9,6,6,3,3) ) , Bmat = Bmat2){
     Amat = getcurve(trans, curve, Bmat)
     -sum(Amat * Bmat)
     }
     #SANN seems to work for this, but is slow. Beware of finite differencing
     # - criterion is non-smooth! 
     optim(c(0,1), compcurve, method = "SANN", Bmat = Bmat2) -> output
     image(Bmat)
     contour(getcurve(output$par), add = T)
    

    Результат:

    Подходит черным, стихи целевой критерий

    Может, не так уж и плохо?

    Возможно, вам придется подделать особенности растеризации, чтобы поработать над другими проблемами. И вы можете настроить, как выполняется оптимизация.

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

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

    person Fhnuzoag    schedule 11.06.2012