2015-08-01 6 views
2

В целях приведения значения интенсивности двух изображений в оттенках серого (в качестве первого шага для дальнейшей обработки) Я написал метод Java, что:Гистограмма Совпадение в Renderscript

  1. преобразует растровые изображения двух изображений в двух int[] массивы, содержащие интенсивности битмапа (я просто беру здесь красный компонент, так как это оттенки серого, т. Е. R = g = b).

    public static int[] bmpToData(Bitmap bmp){ 
    int width = bmp.getWidth(); 
    int height = bmp.getHeight(); 
    int anzpixel = width*height; 
    int [] pixels = new int[anzpixel]; 
    int [] data = new int[anzpixel]; 
    bmp.getPixels(pixels, 0, width, 0, 0, width, height); 
    for (int i = 0 ; i < anzpixel ; i++) { 
    int p = pixels[i]; 
    int r = (p & 0xff0000) >> 16; 
    //int g = (p & 0xff00) >> 8; 
    //int b = p & 0xff; 
    data[i] = r; 
    } 
    return data; 
    } 
    
  2. выравнивает аккумулированной распределения интенсивностей Bitmap 2, что и Bitmap 1

    //aligns the intensity distribution of a grayscale picture moving (given by int[] //data2) the the intensity distribution of a reference picture fixed (given by // int[] data1) 
    public static int[] histMatch(int[] data1, int[] data2){ 
    
        int anzpixel = data1.length; 
        int[] histogram_fixed = new int[256]; 
        int[] histogram_moving = new int[256]; 
        int[] cumhist_fixed = new int[256]; 
        int[] cumhist_moving = new int[256]; 
        int i=0; 
        int j=0; 
    
        //read intensities of fixed und moving in histogram 
        for (int n = 0; n < anzpixel; n++) { 
         histogram_fixed[data1[n]]++; 
         histogram_moving[data2[n]]++; 
        } 
    
        // calc cumulated distributions 
        cumhist_fixed[0]=histogram_fixed[0]; 
        cumhist_moving[0]=histogram_moving[0]; 
        for (i=1; i < 256; ++i) { 
         cumhist_fixed[i] = cumhist_fixed[i-1]+histogram_fixed[i]; 
         cumhist_moving[i] = cumhist_moving[i-1]+histogram_moving [i]; 
        } 
    
        // look-up-table lut[]. For each quantile i of the moving picture search  the 
        // value j of the fixed picture where the quantile is the same as that of moving 
        int[] lut = new int[anzpixel]; 
        j=0; 
        for (i=0; i < 256; ++i){ 
         while(cumhist_fixed[j]< cumhist_moving[i]){ 
         j++; 
         } 
    
         // check, whether the distance to the next-lower intensity is even lower, and if so, take this value 
         if ((j!=0) && ((cumhist_fixed[j-1]- cumhist_fixed[i]) < (cumhist_fixed[j]- cumhist_fixed[i]))){ 
         lut[i]= (j-1); 
         } 
         else { 
         lut[i]= (j); 
         } 
        } 
    
        // apply the lut[] to moving picture. 
        i=0; 
        for (int n = 0; n < anzpixel; n++) { 
         data2[n]=(int) lut[data2[n]]; 
        } 
        return data2; 
    } 
    
  3. преобразует int[] массивы обратно в Bitmap.

    public static Bitmap dataToBitmap(int[] data, int width, int heigth) { 
    int index=0; 
    Bitmap bmp = Bitmap.createBitmap(width, heigth, Bitmap.Config.ARGB_8888); 
    for (int x = 0; x < width; x++) { 
        for (int y = 0; y < heigth; y++) { 
        index=y*width+x; 
        int c = data[index]; 
        bmp.setPixel(x,y,Color.rgb(c, c, c)); 
        } 
    } 
    return bmp; 
    } 
    

Хотя процедура сердечник 2) является простым и быстрым, этапы преобразования 1) и 3) весьма неэффективно. Было бы более чем здорово сделать все это в Renderscript. Но, честно говоря, я полностью потерял это из-за недостающей документации и, хотя есть много впечатляющих примеров того, что Renderscript МОЖЕТ выполнять, я не вижу возможности извлечь выгоду из этих возможностей (без книг, без документа). Любые советы приветствуются!

+1

В чем ваш вопрос? – kittykittybangbang

+0

По крайней мере, покажите нам свой Java-код, чтобы мы знали, что вы хотите реализовать в Renderscript. –

+0

Извините за неточность. Я включил вышеприведенный код, но, к сожалению, не удалось правильно настроить макет. В двух словах, проблема заключается в следующем. Вместо того, чтобы сначала преобразовать два битовых массива в массивы int [] (1.), выполнив фактическое сопоставление гистограмм двух массивов int [] (2.) и преобразуя (сопоставленный) массив int [] обратно в Bitmap (3.) Я хочу сделать все это в Renderscript как одну процедуру, то есть 2 растровых изображения и 1 битмап (совпадающий). – Settembrini

ответ

2

В качестве отправной точки используйте Android Studio для «Импорт образца ...» и выберите «Основной сценарий рендеринга». Это даст вам рабочий проект, который мы сейчас изменим.

Прежде всего, давайте добавим ссылки на ссылки MainActivity. Мы будем использовать их для передачи данных изображений, гистограмм и LUT между Java и Renderscript.

private Allocation mInAllocation; 
private Allocation mInAllocation2; 
private Allocation[] mOutAllocations; 
private Allocation mHistogramAllocation; 
private Allocation mHistogramAllocation2; 
private Allocation mLUTAllocation; 

Затем в onCreate() загрузить другое изображение, которые вы также должны добавить в/Рез/вводимого коэффициента /.

mBitmapIn2 = loadBitmap(R.drawable.cat_480x400); 

В createScript() создают дополнительные распределения:

mInAllocation2 = Allocation.createFromBitmap(mRS, mBitmapIn2); 
    mHistogramAllocation = Allocation.createSized(mRS, Element.U32(mRS), 256); 
    mHistogramAllocation2 = Allocation.createSized(mRS, Element.U32(mRS), 256); 
    mLUTAllocation = Allocation.createSized(mRS, Element.U32(mRS), 256); 

И теперь основная часть (в RenderScriptTask):

  /* 
      * Invoke histogram kernel for both images 
      */ 
      mScript.bind_histogram(mHistogramAllocation); 
      mScript.forEach_compute_histogram(mInAllocation); 

      mScript.bind_histogram(mHistogramAllocation2); 
      mScript.forEach_compute_histogram(mInAllocation2); 


      /* 
      * Variables copied verbatim from your code. 
      */ 
      int []histogram_fixed = new int[256]; 
      int []histogram_moving = new int[256]; 
      int[] cumhist_fixed = new int[256]; 
      int[] cumhist_moving = new int[256]; 
      int i=0; 
      int j=0; 

      // copy computed histograms to Java side 
      mHistogramAllocation.copyTo(histogram_fixed); 
      mHistogramAllocation2.copyTo(histogram_moving); 

      // your code again... 
      // calc cumulated distributions 
      cumhist_fixed[0]=histogram_fixed[0]; 
      cumhist_moving[0]=histogram_moving[0]; 

      for (i=1; i < 256; ++i) { 
       cumhist_fixed[i] = cumhist_fixed[i-1]+histogram_fixed[i]; 
       cumhist_moving[i] = cumhist_moving[i-1]+histogram_moving [i]; 
      } 

      // look-up-table lut[]. For each quantile i of the moving picture search  the 
      // value j of the fixed picture where the quantile is the same as that of moving 
      int[] lut = new int[256]; 
      j=0; 
      for (i=0; i < 256; ++i){ 
       while(cumhist_fixed[j]< cumhist_moving[i]){ 
        j++; 
       } 

       // check, whether the distance to the next-lower intensity is even lower, and if so, take this value 
       if ((j!=0) && ((cumhist_fixed[j-1]- cumhist_fixed[i]) < (cumhist_fixed[j]- cumhist_fixed[i]))){ 
        lut[i]= (j-1); 
       } 
       else { 
        lut[i]= (j); 
       } 
      } 

      // copy the LUT to Renderscript side 
      mLUTAllocation.copyFrom(lut); 
      mScript.bind_LUT(mLUTAllocation); 

      // Apply LUT to the destination image 
      mScript.forEach_apply_histogram(mInAllocation2, mInAllocation2); 


      /* 
      * Copy to bitmap and invalidate image view 
      */ 
      //mOutAllocations[index].copyTo(mBitmapsOut[index]); 

      // copy back to Bitmap in preparation for viewing the results 
      mInAllocation2.copyTo((mBitmapsOut[index])); 

Пара заметок:

  • В вашей части код я также исправил LUT размер выделения - требуется только 256 местоположений,
  • Как вы можете видеть, я оставил расчет кумулятивной гистограммы и LUT на стороне Java. Их довольно сложно эффективно распараллеливать из-за зависимостей данных и небольших масштабов вычислений, но, учитывая последнее, я не думаю, что это проблема.

И наконец, код Renderscript. Единственной неочевидной частью является использование rsAtomicInc() для увеличения значений в гистограммах - это необходимо из-за того, что потенциально много потоков пытаются увеличить один и тот же бит одновременно.

#pragma version(1) 
#pragma rs java_package_name(com.example.android.basicrenderscript) 
#pragma rs_fp_relaxed 

int32_t *histogram; 
int32_t *LUT; 

void __attribute__((kernel)) compute_histogram(uchar4 in) 
{ 
    volatile int32_t *addr = &histogram[in.r]; 
    rsAtomicInc(addr); 
} 

uchar4 __attribute__((kernel)) apply_histogram(uchar4 in) 
{ 
    uchar val = LUT[in.r]; 
    uchar4 result; 
    result.r = result.g = result.b = val; 
    result.a = in.a; 

    return(result); 
} 
+0

Большое спасибо Laubzega за эту потрясающую работу. Я вижу, что вы используете два ядра, одно для чтения - в гистограммах, одно для сопоставления гистограммы изображения2 с производным LUT. Это концептуальное решение, которое я искал. К сожалению, при ее реализации я по-прежнему борюсь с некоторыми проблемами Android Studio. Я настроил новый проект и поместил rs-код в файл с именем histm.rs в папке «rs» на том же уровне, что и Java-Folder. Теперь по какой-то причине он не распознает инициализацию: private ScriptC_histm mScript. – Settembrini

+0

Не распознает, как в «не компилируется», или просто «IDE подчеркивает как ошибку»? В общем, вам также необходимо изменить сценарий [Градл] проекта (http://stackoverflow.com/questions/19658145/how-to-use-the-renderscript-support-library-with-gradle/22976675#22976675). Вот почему я рекомендовал начать с «File/Import Sample ...». –

+0

Он не компилируется и после очистки проекта он обнаруживает проблему с R-файлом. Я не вижу ничего особенного в сценарии градации. Сначала я попробовал использовать пример import renderscript, но это не работало из-за некоторого вмешательства в существующий код. Я думаю, мне нужно просто попробовать еще кое-что. – Settembrini

Смежные вопросы