Як я повторюю кожну клітинку безперервним растром?


13

Дивіться це посилання для отримання детальної інформації.

Проблема:

Я хочу провести цикл через суцільний растр (той, у якого немає таблиці атрибутів), комірку за коміркою, і отримати значення комірки. Я хочу взяти ці значення та запустити на них умовні умови, емулюючи кроки алгебри карти, детально описані нижче, не використовуючи фактично растровий калькулятор.

На запит коментарів, наведених нижче, я додав деталі, що пояснюють проблему та обґрунтовують необхідність впровадження методу як такого в розділі нижче під назвою "Необхідний аналіз:".

Пропонований нижче аналіз, хоч і має відношення до моєї проблеми, надаючи передумови, не потребує реалізації відповіді. Обсяг питання стосується лише повторення через суцільний растр для отримання / встановлення значень комірок.

Аналіз необхідний:

Якщо виконано будь-яке з наступних умов, дайте вихідній комірці значення 1. Лише для вихідної комірки задайте значення 0, якщо жодна з умов не виконується.

Умова 1: Якщо значення комірки більше клітинок верхньої та нижньої, дайте значення 1:

Con("raster" > FocalStatistics("raster", NbrIrregular("C:\filepath\kernel_file.txt"), "MAXIMUM"), 1, 0)

Де файл ядра виглядає так:

3 3 
0 1 0
0 0 0
0 1 0

Умова 2: Якщо значення комірки більше лівої та правої комірок, дайте значення 1:

Con("raster" > FocalStatistics("raster", NbrIrregular("C:\filepath\kernel_file.txt"), "MAXIMUM"), 1, 0)

Де файл ядра виглядає так:

3 3 
0 0 0
1 0 1
0 0 0  

Умова 3: Якщо значення комірки більше клітинок верхнього та нижнього прямого кута, дайте значення 1:

Con("raster" > FocalStatistics("raster", NbrIrregular("C:\filepath\kernel_file.txt"), "MAXIMUM"), 1, 0)

Де файл ядра виглядає так:

3 3 
1 0 0
0 0 0
0 0 1 

Умова 4: Якщо значення комірки перевищує нижню ліву та прямолінійну клітинку, дайте значення 1:

Con("raster" > FocalStatistics("raster", NbrIrregular("C:\filepath\kernel_file.txt"), "MAXIMUM"), 1, 0)

Де файл ядра виглядає так:

3 3 
0 0 1
0 0 0
1 0 0 

Умова 5: Якщо будь- яка з сусідніх комірок має значення EQUAL для центральної комірки, дайте вихідному растру значення 1 ( використовуючи фокусну різноманітність з двома найближчими розрахунками сусідства )

Чому б не використовувати алгебру карти?

Нижче було відмічено, що мою проблему можна вирішити за допомогою алгебри карт, але, як видно вище, це загальна сума шести растрових обчислень, плюс один, щоб об'єднати всі створені растри разом. Мені здається, що набагато ефективніше переходити по клітинах і робити всі порівняння одразу в кожній клітині, замість того, щоб проглядати кожну окремо сім разів і використовувати досить небагато пам'яті для створення семи растрових.

Як слід напасти на проблему?

Наведене вище посилання радить використовувати інтерфейс IPixelBlock, однак з документації ESRI незрозуміло, чи дійсно ви отримуєте доступ до самого значення однієї комірки через IPixelBlock, або ви отримуєте доступ до декількох значень комірок від розміру встановленого IPixelBlock. Хороша відповідь повинна запропонувати метод доступу до значень комірок безперервного растру та надати пояснення методології, що стоїть за кодом, якщо це не очевидно.

Підсумовуючи:

Який найкращий метод провести цикл через кожну клітинку в НЕПЕРЕЧНОМ растровій (у якої немає таблиці атрибутів ) для доступу до її значень комірок?

Для гарної відповіді не потрібно виконувати описані вище етапи аналізу, потрібно лише надати методологію доступу до значень комірок растру.


4
Працювати в растрі майже кожну клітинку майже завжди не потрібно. Чи можете ви надати більше інформації про те, що ви намагаєтесь зробити?
користувач2856

2
@Luke правильний: на сьогоднішній день найкращим способом виконати ітеративний растровий обчислення в будь-якому ГІС є уникнення явного циклічного перегляду клітинок, тому що під кришкою будь-яка петля, яку потрібно зробити, вже оптимізована. Натомість шукайте спосіб використовувати функцію алгебри карт, надану ГІС, якщо це взагалі можливо. Якби ви описували свій аналіз, ви можете отримати корисні відповіді, які використовують такий підхід.
whuber

@Luke Я додав деталі аналізу.
Conor

1
Дякую за роз’яснення, Коноре. Я погоджуюся, що якщо ваш ГІС має значні накладні витрати для кожного растрового обчислення, написання власного циклу може бути більш ефективним. З цікавості, що задумане тлумачення цієї (незвичної) сукупності умов?
whuber

1
@whuber Це для операцій з виявлення ребер для створення векторних багатокутників з мого растру. Додаток концептуально подібний до визначення басейнів гідрології з ДЕМ (подумайте про центральну клітинку в статистиці мікрорайонів, перераховану вище, як про «пік», з якого вода стікатиме вниз), але знаходиться поза сферою гідрології. Раніше я використовував для цієї мети потоки та басейнові растри, але вони схильні до помилок у моєму остаточному аналізі, оскільки властивості цих методів не є саме тим, що мені потрібно.
Conor

Відповіді:


11

Я бачу, що це вже вирішено оригінальним плакатом (OP), але я опублікую просте рішення в python на всякий випадок, якщо хтось у майбутньому зацікавиться різними способами вирішити цю проблему. Я частково відкриваю програмне забезпечення, тому ось рішення з використанням GDAL в python:

import gdal

#Set GeoTiff driver
driver = gdal.GetDriverByName("GTiff")
driver.Register()

#Open raster and read number of rows, columns, bands
dataset = gdal.Open(filepath)
cols = dataset.RasterXSize
rows = dataset.RasterYSize
allBands = dataset.RasterCount
band = dataset.GetRasterBand(1)

#Get array of raster cell values.  The two zeros tell the 
#iterator which cell to start on and the 'cols' and 'rows' 
#tell the iterator to iterate through all columns and all rows.
def get_raster_cells(band,cols,rows):
    return band.ReadAsArray(0,0,cols,rows)

Реалізуйте функцію так:

#Bind array to a variable
rasterData = get_raster_cells(band,cols,rows)

#The array will look something like this if you print it
print rasterData
> [[ 1, 2, 3 ],
   [ 4, 5, 6 ],
   [ 7, 8, 9 ]]

Потім повторіть свої дані за допомогою вкладеного циклу:

for row in rasterData:
    for val in row:
        print val
> 1
  2
  3
  4...

Або, можливо, ви хочете розрівняти 2-D масив із розумінням списку:

flat = [val for row in rasterData for val in row]

У будь-якому разі, під час ітерації даних по клітині на основі осередку можна кидати деякі умови в цикл для зміни / редагування значень. Дивіться цей сценарій, який я написав для різних способів доступу до даних: https://github.com/azgs/hazards-viewer/blob/master/python/zonal_stats.py .


Мені подобається простота і витонченість цього рішення. Я зачекаю ще кілька днів, і якщо більше ніхто не прийме рішення рівної або більшої якості, я додамо теги, щоб розширити сферу питання на благо громади та нагородити вас винагородою.
Conor

Дякую, @Conor! На моєму місці роботи ми зустріли подібну проблему на початку цього тижня, і тому я вирішив її, написавши клас з GDAL / python. Зокрема, нам знадобився серверний метод для обчислення середнього значення площі растра, заданого лише обмежувальним вікном від користувача на нашому клієнтському додатку. Як ви вважаєте, було б корисно, якби я додав решту класу, про який писав?
asonnenschein

Додавання коду, який показує, як читати отриманий двовимірний масив та редагувати його значення, було б корисним.
Conor

9

Оновлення! Рішення нумеру:

import arcpy
import numpy as np

in_ras = path + "/rastername"

raster_Array = arcpy.RasterToNumPyArray(in_ras)
row_num = raster_Array.shape[0]
col_num = raster_Array.shape[1]
cell_count = row_num * row_num

row = 0
col = 0
temp_it = 0

while temp_it < cell_count:
    # Insert conditional statements
    if raster_Array[row, col] > 0:
        # Do something
        val = raster_Array[row, col]
        print val
    row+=1
    if col > col_num - 1:
        row = 0
        col+=1

Таким чином, повернення готового масиву до растрового за допомогою arcpy є проблематичним. arcpy.NumPyArrayToRaster є білочка і має тенденцію до повторного визначення розрізів, навіть якщо ви подаєте їй свої координати LL.

Я вважаю за краще зберегти як текст.

np.savetxt(path + "output.txt", output, fmt='%.10f', delimiter = " ")

Я запускаю Python як 64 біт для швидкості - на даний момент це означає, що я не можу подати numpy.savetxt заголовок. Тож я маю відкрити вихід і додати заголовок ASCII, який хоче Arc, перш ніж перетворити ASCII в Raster

File_header = "NCOLS xxx" + '\n'+ "NROWS xxx" + '\n' + "XLLCORNER xxx"+'\n'+"YLLCORNER xxx"+'\n'+"CELLSIZE xxx"+'\n'+"NODATA_VALUE xxx"+'\n'

Версія numpy запускає мою растрову зміну, множення та додавання набагато швидше (1000 ітерацій за 2 хвилини), ніж версія arcpy (1000 ітерацій за 15 хв)

СТАРА ВЕРСІЯ Я можу видалити це пізніше. Я просто написав подібний сценарій. Я спробував перетворитись на точки та за допомогою курсору пошуку. Я отримав лише 5000 ітерацій за 12 годин. Отже, я шукав інший шлях.

Мій спосіб зробити це полягає в перегляді координат центру комірок кожної комірки. Я починаю у верхньому лівому куті і рухаюся справа наліво. В кінці рядка я рухаюся вниз по рядку і знову починаю зліва. У мене растр на 240 м з 2603 стовпцями та 2438 рядками, так що загалом 6111844 комірок. Я використовую змінну ітератора і цикл час. Дивіться нижче

Кілька приміток: 1 - вам потрібно знати координати протяжності

2 - запустіть з точковими координатами для центру комірки - перемістіться на 1/2 розміру комірки від значень міри

3 - Мій сценарій використовує значення комірки для витягування растрового значення, а потім переміщує цей растр у центр вихідної комірки. Це додає до нульового растру для розширення масштабу перед додаванням у остаточний растр. Це лише приклад. Ви можете помістити сюди свої умовні висловлювання (друге, якщо твердження в циклі while).

4 - Цей сценарій передбачає, що всі растрові значення можуть бути передані у вигляді цілих чисел. Це означає, що вам потрібно спочатку позбутися даних про відсутність даних. Con IsNull.

6 - Я все ще не задоволений цим і працюю над тим, щоб вийняти це з архпії повністю. Я вважаю, що я вважаю, що це масивні масиви і робити математику там, а потім повернути його до Arc.

ULx = 959415 ## coordinates for the Upper Left of the entire raster 
ULy = 2044545
x = ULx ## I redefine these if I want to run over a smaller area
y = ULy
temp_it = 0

while temp_it < 6111844: # Total cell count in the data extent
        if x <= 1583895 and y >= 1459474: # Coordinates for the lower right corner of the raster
           # Get the Cell Value
           val_result = arcpy.GetCellValue_management(inraster, str(x)+" " +str(y), "1")
           val = int(val_result.getOutput(0))
        if val > 0: ## Here you could insert your conditional statements
            val_pdf = Raster(path + "pdf_"str(val))
            shift_x  =  ULx - x # This will be a negative value
            shift_y = ULy - y # This will be a positive value
            arcpy.Shift_management(val_pdf, path+ "val_pdf_shift", str(-shift_x), str(-shift_y))
            val_pdf_shift = Raster(path + "val_pdf_shift")
            val_pdf_sh_exp = CellStatistics([zeros, val_pdf_shift], "SUM", "DATA")
            distr_days = Plus(val_pdf_sh_exp, distr_days)
        if temp_it % 20000 == 0: # Just a print statement to tell me how it's going
                print "Iteration number " + str(temp_it) +" completed at " + str(time_it)
        x += 240 # shift x over one column
        if x > 1538295: # if your at the right hand side of a row
            y = y-240 # Shift y down a row
            x = 959415 # Shift x back to the first left hand column
        temp_it+=1

distr_days.save(path + "Final_distr_days")

4

Спробуйте використовувати IGridTable, ICursor, IRow. Цей фрагмент коду призначений для оновлення значень растрових комірок, однак він показує основи ітерації:

Як я можу додати нове поле у ​​таблицю атрибутів растрових та пройти цикл через нього?

Public Sub CalculateArea(raster As IRaster, areaField As String)
    Dim bandCol As IRasterBandCollection
    Dim band As IRasterBand

    Set bandCol = raster
    Set band = bandCol.Item(0)

    Dim hasTable As Boolean
    band.hasTable hasTable
    If (hasTable = False) Then
        Exit Sub
    End If    

    If (AddVatField(raster, areaField, esriFieldTypeDouble, 38) = True) Then
        ' calculate cell size
        Dim rstProps As IRasterProps
        Set rstProps = raster

        Dim pnt As IPnt
        Set pnt = rstProps.MeanCellSize

        Dim cellSize As Double
        cellSize = (pnt.X + pnt.Y) / 2#

        ' get fields index
        Dim attTable As ITable
        Set attTable = band.AttributeTable

        Dim idxArea As Long, idxCount As Long
        idxArea = attTable.FindField(areaField)
        idxCount = attTable.FindField("COUNT")

        ' using update cursor
        Dim gridTableOp As IGridTableOp
        Set gridTableOp = New gridTableOp

        Dim cellCount As Long, cellArea As Double

        Dim updateCursor As ICursor, updateRow As IRow
        Set updateCursor = gridTableOp.Update(band.RasterDataset, Nothing, False)
        Set updateRow = updateCursor.NextRow()
        Do Until updateRow Is Nothing
            cellCount = CLng(updateRow.Value(idxCount))
            cellArea = cellCount * (cellSize * cellSize)

            updateRow.Value(idxArea) = cellArea
            updateCursor.updateRow updateRow

            Set updateRow = updateCursor.NextRow()
        Loop

    End If
End Sub

Після переходу до таблиці ви можете отримати конкретне значення рядка поля, використовуючи row.get_Value(yourfieldIndex). Якщо ви Google

arcobjects row.get_Value

ви повинні мати можливість отримати чимало прикладів, що це показують.

Сподіваюся, що це допомагає.


1
Я, на жаль, нехтував зауваженням і редагую в своєму первісному запитанні вище, що мій растр має багато безперервних значень, що складаються з великих подвійних значень, і як такий цей метод не працюватиме, оскільки мій растр не має значень таблиці атрибутів.
Conor

4

Як щодо цього, як радикальної ідеї, це вимагатиме від вас програмування в python або ArcObjects.

  1. Перетворіть вашу сітку в точковий клас класів.
  2. Створіть поля XY та заповніть.
  3. Завантажте точки у словник, де ключ - це рядок X, Y, а елемент - значення комірки.
  4. Перегляньте свій словник і для кожної точки опрацюйте 8 навколишніх осередків XY.
  5. Отримайте їх зі свого словника і протестуйте свої правила, як тільки ви знайдете значення, що відповідає дійсності, ви можете пропустити решту тестів.
  6. Запишіть результати в інший словник, а потім перетворіть назад в сітку, спочатку створивши точку FeatureClass, а потім перетворіть точки в сітку.

2
Перетворюючи на набір функцій точок, ця ідея усуває дві якості представлення даних на основі растру, які роблять його таким ефективним: (1) пошук сусідів - надзвичайно проста операція в постійному часі і (2), оскільки явне зберігання локацій не потрібна, вимоги оперативної пам’яті, диска та вводу / виводу мінімальні. Таким чином, хоча цей підхід спрацює, важко знайти будь-яку причину його рекомендувати.
whuber

Дякуємо за вашу відповідь Hornbydd. Я все в порядку з реалізацією такого методу, але схоже, що кроки 4 і 5 не будуть дуже ефективними для обчислень. Мої растри матимуть як мінімум 62 500 комірок (мінімальна роздільна здатність для мого растру, яку я встановила, - 250 комірок x 250 комірок, але роздільна здатність може, як правило, складається з набагато більше), і мені доведеться зробити просторовий запит для кожної умови виконання моїх порівнянь ... Оскільки у мене 6 умов, це було б 6 * 62500 = 375000 просторових запитів. Мені краще з алгеброю карти. Але дякую за цей новий спосіб перегляду проблеми. Отримано.
Conor

Ви не можете просто перетворити його в ASCII, а потім використовувати програму, на зразок R, щоб зробити обчислення?
Олівер Бурдекін

Плюс у мене є аплет Java, який я написав, що його можна легко змінити, щоб задовольнити ваші умови вище. Це був просто алгоритм вирівнювання, але оновлення було б досить легко зробити.
Олівер Бурдекін

Поки можна викликати програму з платформи .NET для користувача, у якого встановлені лише .NET Framework 3.5 та ArcGIS 10. Програма є відкритим кодом, і я маю на увазі, що це єдині вимоги до програмного забезпечення, коли їх постачають кінцевим користувачам. Якщо ваша відповідь може бути реалізована для задоволення цих двох вимог, вона вважатиметься правильною відповіддю. Я додам тег версії до питання, а також для уточнення.
Conor

2

Рішення:

Я вирішив це раніше сьогодні. Код є адаптацією цього методу . Концепція цього не була надзвичайно складною, коли я зрозумів, що насправді роблять об'єкти, що використовуються для взаємодії з растром. Наведений нижче метод має два набори вхідних даних (inRasterDS та outRasterDS). Вони обидва того ж набору даних, я щойно зробив копію inRasterDS і передав її в метод як outRasterDS. Таким чином, вони обидва мають однаковий ступінь, просторове посилання і т. Д. Метод зчитує значення з inRasterDS, комірку за клітиною, і робить порівняння найближчих сусідів. Він використовує результати цих порівнянь як збережені значення у outRasterDS.

Процес:

Я використовував IRasterCursor -> IPixelBlock -> SafeArray для отримання значень пікселів, а IRasterEdit для запису нових на растр. Коли ви створюєте IPixelBlock, ви повідомляєте апарату розмір та розташування області, в яку ви хочете прочитати / записати. Якщо ви хочете відредагувати лише нижню половину растру, ви встановите це як параметри IPixelBlock. Якщо ви хочете перевести цикл на весь растр, вам потрібно встановити IPixelBlock, рівний розміру всієї растрової. Я роблю це в наведеному нижче методі, передаючи розмір IRasterCursor (pSize), а потім отримуючи PixelBlock від растрового курсору.

Інший ключ полягає в тому, що вам потрібно використовувати SafeArray для взаємодії зі значеннями в цьому методі. Ви отримуєте IPixelBlock від IRasterCursor, а потім SafeArray від IPixelBlock. Потім ви читаєте і пишете в SafeArray. Закінчивши читання / запис у SafeArray, запишіть весь SafeArray назад в IPixelBlock, потім запишіть свій IPixelBlock в IRasterCursor, а потім, нарешті, використовуйте IRasterCursor, щоб встановити місце для початку запису, а IRasterEdit зробити самому запис. На цьому останньому кроці ви фактично редагуєте значення набору даних.

    public static void CreateBoundaryRaster(IRasterDataset2 inRasterDS, IRasterDataset2 outRasterDS)
    {
        try
        {
            //Create a raster. 
            IRaster2 inRaster = inRasterDS.CreateFullRaster() as IRaster2; //Create dataset from input raster
            IRaster2 outRaster = outRasterDS.CreateFullRaster() as IRaster2; //Create dataset from output raster
            IRasterProps pInRasterProps = (IRasterProps)inRaster;
            //Create a raster cursor with a pixel block size matching the extent of the input raster
            IPnt pSize = new DblPnt();
            pSize.SetCoords(pInRasterProps.Width, pInRasterProps.Height); //Give the size of the raster as a IPnt to pass to IRasterCursor
            IRasterCursor inrasterCursor = inRaster.CreateCursorEx(pSize); //Create IRasterCursor to parse input raster 
            IRasterCursor outRasterCursor = outRaster.CreateCursorEx(pSize); //Create IRasterCursor to parse output raster
            //Declare IRasterEdit, used to write the new values to raster
            IRasterEdit rasterEdit = outRaster as IRasterEdit;
            IRasterBandCollection inbands = inRasterDS as IRasterBandCollection;//set input raster as IRasterBandCollection
            IRasterBandCollection outbands = outRasterDS as IRasterBandCollection;//set output raster as IRasterBandCollection
            IPixelBlock3 inpixelblock3 = null; //declare input raster IPixelBlock
            IPixelBlock3 outpixelblock3 = null; //declare output raster IPixelBlock
            long blockwidth = 0; //store # of columns of raster
            long blockheight = 0; //store # of rows of raster

            //create system array for input/output raster. System array is used to interface with values directly. It is a grid that overlays your IPixelBlock which in turn overlays your raster.
            System.Array inpixels; 
            System.Array outpixels; 
            IPnt tlc = null; //set the top left corner

            // define the 3x3 neighborhood objects
            object center;
            object topleft;
            object topmiddle;
            object topright;
            object middleleft;
            object middleright;
            object bottomleft;
            object bottommiddle;
            object bottomright;

            long bandCount = outbands.Count; //use for multiple bands (only one in this case)

            do
            {

                inpixelblock3 = inrasterCursor.PixelBlock as IPixelBlock3; //get the pixel block from raster cursor
                outpixelblock3 = outRasterCursor.PixelBlock as IPixelBlock3;
                blockwidth = inpixelblock3.Width; //set the # of columns in raster
                blockheight = inpixelblock3.Height; //set the # of rows in raster
                outpixelblock3.Mask(255); //set any NoData values

                for (int k = 0; k < bandCount; k++) //for every band in raster (will always be 1 in this case)
                {
                    //Get the pixel array.
                    inpixels = (System.Array)inpixelblock3.get_PixelData(k); //store the raster values in a System Array to read
                    outpixels = (System.Array)outpixelblock3.get_PixelData(k); //store the raster values in a System Array to write
                    for (long i = 1; i < blockwidth - 1; i++) //for every column (except outside columns)
                    {
                        for (long j = 1; j < blockheight - 1; j++) //for every row (except outside rows)
                        {
                            //Get the pixel values of center cell and  neighboring cells

                            center = inpixels.GetValue(i, j);

                            topleft = inpixels.GetValue(i - 1, j + 1);
                            topmiddle = inpixels.GetValue(i, j + 1);
                            topright = inpixels.GetValue(i + 1, j + 1);
                            middleleft = inpixels.GetValue(i - 1, j);
                            middleright = inpixels.GetValue(i + 1, j);
                            bottomleft = inpixels.GetValue(i - 1, j - 1);
                            bottommiddle = inpixels.GetValue(i, j - 1);
                            bottomright = inpixels.GetValue(i - 1, j - 1);


                            //compare center cell value with middle left cell and middle right cell in a 3x3 grid. If true, give output raster value of 1
                            if ((Convert.ToDouble(center) >= Convert.ToDouble(middleleft)) && (Convert.ToDouble(center) >= Convert.ToDouble(middleright)))
                            {
                                outpixels.SetValue(1, i, j);
                            }


                            //compare center cell value with top middle and bottom middle cell in a 3x3 grid. If true, give output raster value of 1
                            else if ((Convert.ToDouble(center) >= Convert.ToDouble(topmiddle)) && (Convert.ToDouble(center) >= Convert.ToDouble(bottommiddle)))
                            {
                                outpixels.SetValue(1, i, j);
                            }

                            //if neither conditions are true, give raster value of 0
                            else
                            {

                                outpixels.SetValue(0, i, j);
                            }
                        }
                    }
                    //Write the pixel array to the pixel block.
                    outpixelblock3.set_PixelData(k, outpixels);
                }
                //Finally, write the pixel block back to the raster.
                tlc = outRasterCursor.TopLeft;
                rasterEdit.Write(tlc, (IPixelBlock)outpixelblock3);
            }
            while (inrasterCursor.Next() == true && outRasterCursor.Next() == true);
            System.Runtime.InteropServices.Marshal.ReleaseComObject(rasterEdit);


        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

    }

1

Растрові дані AFAIK можна прочитати трьома способами:

  • по клітині (неефективно);
  • за зображенням (досить ефективно);
  • блоками (найефективніший спосіб).

Не вигадуючи колесо, пропоную прочитати ці освічуючі слайди Кріса Гаррарда.

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

На обчислювальній стороні, замість цього, я повинен використовувати gdalfilter.py та неявно підхід VRT KernelFilteredSource для того, щоб застосувати необхідні фільтри і, перш за все, уникнути важких розрахунків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.