ฉันจะวนซ้ำทุกเซลล์ในแรสเตอร์ต่อเนื่องได้อย่างไร


13

ดูลิงค์นี้สำหรับรายละเอียดเพิ่มเติม

ปัญหา:

ฉันต้องการวนรอบraster อย่างต่อเนื่อง (ที่ไม่มีตารางคุณลักษณะ), เซลล์โดยเซลล์และรับค่าของเซลล์ ฉันต้องการใช้ค่าเหล่านั้นและเรียกใช้ conditionals กับพวกเขาเลียนแบบขั้นตอนพีชคณิตแผนที่รายละเอียดด้านล่างโดยไม่ต้องใช้เครื่องคิดเลขแรสเตอร์

ตามคำขอของความคิดเห็นด้านล่างฉันได้เพิ่มรายละเอียดที่ให้ข้อมูลพื้นฐานเกี่ยวกับปัญหาและให้เหตุผลถึงความจำเป็นในการใช้วิธีการดังกล่าวในส่วนด้านล่างที่เรียกว่า "การวิเคราะห์ที่จำเป็น:"

การวิเคราะห์ที่เสนอด้านล่างในขณะที่เกี่ยวข้องกับปัญหาของฉันโดยการให้ข้อมูลพื้นฐานไม่จำเป็นต้องมีคำตอบ ขอบเขตของคำถามเกี่ยวข้องกับการวนซ้ำผ่านแรสเตอร์อย่างต่อเนื่องเพื่อรับ / ตั้งค่าของเซลล์

การวิเคราะห์ที่จำเป็น:

หากเงื่อนไขใด ๆ ต่อไปนี้เป็นจริงให้กำหนดค่าเซลล์เอาต์พุตเป็น 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:หากค่าของเซลล์มากกว่าเซลล์ topleft และ bottomright ให้ค่าเป็น 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:หากค่าของเซลล์มากกว่าด้านล่างและเซลล์ topright ให้ค่า 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:ถ้าใด ๆหนึ่งในเซลล์ที่อยู่ติดกันมีค่าเท่ากับศูนย์มือถือที่ให้ผลผลิตแรสเตอร์มูลค่า 1 ( ใช้ความหลากหลายโฟกัสกับสองคำนวณเขตที่ใกล้ที่สุด )

ทำไมไม่ใช้พีชคณิตแผนที่?

มันได้รับการบันทึกไว้ด้านล่างว่าปัญหาของฉันสามารถแก้ไขได้โดยใช้พีชคณิตแผนที่ แต่เท่าที่เห็นด้านบนนี้เป็นการคำนวณแรสเตอร์ทั้งหมดหกครั้งรวมกับการรวมแรสเตอร์ทั้งหมดที่สร้างขึ้นด้วยกัน มันดูเหมือนว่าฉันว่ามันมากมีประสิทธิภาพมากขึ้นไปเซลล์จากเซลล์และทำทุกการเปรียบเทียบในครั้งเดียวในเซลล์แทนการวนลูปผ่านแต่ละเจ็ดครั้งและใช้ประโยชน์ไม่น้อยของหน่วยความจำในการสร้างเจ็ดเชิงภาพแต่ละ

ปัญหานี้จะถูกโจมตีได้อย่างไร?

ลิงค์ด้านบนแนะนำให้ใช้อินเทอร์เฟซ IPixelBlock แต่ไม่ชัดเจนจากเอกสารของ ESRI ไม่ว่าคุณจะเข้าถึงค่าเซลล์เดียวผ่าน IPixelBlock หรือหากคุณเข้าถึงหลายค่าเซลล์จากขนาดของ IPixelBlock ที่คุณตั้งค่า คำตอบที่ดีควรแนะนำวิธีการในการเข้าถึงค่าเซลล์ของแรสเตอร์อย่างต่อเนื่องและให้คำอธิบายเกี่ยวกับวิธีการที่อยู่เบื้องหลังรหัสถ้าไม่ชัดเจน

สรุป:

เป็นวิธีที่ดีที่สุดในการวนซ้ำทุกเซลล์ในแรสเตอร์อย่างต่อเนื่อง (ซึ่งไม่มีตารางคุณลักษณะ ) เพื่อเข้าถึงค่าเซลล์ของมันคืออะไร?

คำตอบที่ดีไม่จำเป็นต้องใช้ขั้นตอนการวิเคราะห์ที่อธิบายไว้ข้างต้น แต่ต้องการเพียงวิธีการในการเข้าถึงค่าเซลล์ของแรสเตอร์


4
มันไม่จำเป็นที่จะต้องวนซ้ำทุก ๆ เซลล์ในแรสเตอร์ คุณสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่คุณพยายามจะทำอย่างไร
2856

2
@Luke ถูกต้อง: วิธีที่ดีที่สุดในการคำนวณ raster ซ้ำใน GIS ใด ๆ คือการหลีกเลี่ยงการวนลูปผ่านเซลล์อย่างชัดเจน ให้หาวิธีใช้ฟังก์ชันพีชคณิตแผนที่ที่จัดทำโดย GIS แทนหากเป็นไปได้ หากคุณต้องอธิบายการวิเคราะห์ของคุณคุณอาจได้รับคำตอบที่เป็นประโยชน์ซึ่งใช้วิธีการดังกล่าว
whuber

@ ลุคฉันได้เพิ่มรายละเอียดของการวิเคราะห์
Conor

1
ขอบคุณสำหรับการชี้แจง Conor ฉันยอมรับว่าหาก GIS ของคุณมีค่าใช้จ่ายสูงสำหรับการคำนวณแรสเตอร์แต่ละครั้งการเขียนลูปของคุณเองอาจมีประสิทธิภาพมากกว่า จากการอยากรู้อยากเห็นการตีความตามเงื่อนไข (ผิดปกติ) ชุดนี้คืออะไร?
whuber

1
@whuber สำหรับการตรวจจับขอบเพื่อสร้างเวกเตอร์รูปหลายเหลี่ยมจากแรสเตอร์ของฉัน แอปพลิเคชันนั้นมีแนวคิดคล้ายกับการระบุแอ่งน้ำอุทกวิทยาจาก DEM (คิดว่าเซลล์กลางในสถิติพื้นที่ใกล้เคียงที่ระบุไว้ข้างต้นว่าเป็น "จุดสูงสุด" ที่น้ำจะไหลลงมาจาก) แต่อยู่นอกเขตอุทกวิทยา ก่อนหน้านี้ฉันเคยใช้ Flow Direction และ Basin Rasters เพื่อจุดประสงค์นี้ แต่สิ่งเหล่านี้มีแนวโน้มที่จะเกิดข้อผิดพลาดในการวิเคราะห์ขั้นสุดท้ายของฉันเนื่องจากคุณสมบัติของวิธีการเหล่านี้ไม่ตรงตามที่ฉันต้องการ
Conor

คำตอบ:


11

ฉันเห็นสิ่งนี้ได้รับการแก้ไขแล้วโดย Original Poster (OP) แต่ฉันจะโพสต์คำตอบง่ายๆใน python ในกรณีที่ทุกคนในอนาคตสนใจวิธีต่างๆในการแก้ปัญหานี้ ฉันเป็นบางส่วนของซอฟต์แวร์โอเพนซอร์สดังนั้นนี่เป็นวิธีแก้ปัญหาโดยใช้ GDAL ในหลาม:

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 มิติของคุณเรียบด้วยการเข้าใจรายการ:

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

การเพิ่มโค้ดที่แสดงวิธีอ่านอาเรย์แบบ 2 มิติที่คุณดึงมาและการแก้ไขค่าของมันจะเป็นประโยชน์
Conor

9

Update! วิธีการแก้ปัญหา numpy:

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

ดังนั้นการทำให้อาเรย์เสร็จแล้วกลับไปที่ raster โดยใช้อาร์คซี่นั้นลำบาก arcpy.NumPyArrayToRaster เป็น squirrelly และมีแนวโน้มที่จะกำหนดขอบเขตใหม่แม้ว่าคุณจะป้อนพิกัด 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'

เวอร์ชันที่ใช้รันแรสเตอร์แรนด์การคูณและการเพิ่มเร็วขึ้นมาก (1,000 ครั้งใน 2 นาที) กว่าเวอร์ชั่นอาร์คปี (1,000 ครั้งใน 15 นาที)

รุ่นเก่าฉันสามารถลบได้ในภายหลังฉันเพิ่งเขียนสคริปต์ที่คล้ายกัน ฉันพยายามแปลงเป็นคะแนนและใช้เคอร์เซอร์ค้นหา ฉันได้รับเพียง 5,000 รอบใน 12 ชั่วโมง ดังนั้นฉันจึงหาวิธีอื่น

วิธีของฉันในการทำเช่นนี้คือการย้ำผ่านพิกัดศูนย์เซลล์ของแต่ละเซลล์ ฉันเริ่มที่มุมซ้ายบนแล้วเลื่อนจากขวาไปซ้าย ในตอนท้ายของแถวฉันเลื่อนลงแถวและเริ่มอีกครั้งที่ด้านซ้าย ฉันมีแรสเตอร์ 240 ม. ที่มี 2603 คอลัมน์และ 2438 แถวดังนั้นทั้งหมด 6111844 เซลล์ทั้งหมด ฉันใช้ตัวแปรตัววนซ้ำและวนรอบสักครู่ ดูด้านล่าง

หมายเหตุเล็กน้อย: 1 - คุณต้องรู้พิกัดของขอบเขต

2 - วิ่งด้วยพิกัดจุดสำหรับศูนย์เซลล์ - ย้าย 1/2 ขนาดเซลล์จากค่าขอบเขต

3 - สคริปต์ของฉันใช้ค่าเซลล์เพื่อดึงแรสเตอร์เฉพาะค่าจากนั้นเลื่อนแรสเตอร์นี้ไปที่กึ่งกลางเซลล์เดิม สิ่งนี้จะเพิ่มเป็นศูนย์แรสเตอร์เพื่อขยายขอบเขตก่อนที่จะเพิ่มเข้าไปในแรสเตอร์สุดท้าย นี่เป็นเพียงตัวอย่าง คุณสามารถใส่คำสั่งแบบมีเงื่อนไขของคุณได้ที่นี่ (ข้อที่สองถ้าคำสั่งอยู่ใน while loop)

4 - สคริปต์นี้ถือว่าค่า raster ทั้งหมดสามารถถูกแปลงเป็นจำนวนเต็มได้ ซึ่งหมายความว่าคุณต้องกำจัดข้อมูลออกก่อน Con IsNull

6 - ฉันยังไม่มีความสุขกับสิ่งนี้และฉันกำลังพยายามที่จะกำจัด arcpy ออกไปโดยสิ้นเชิง ฉันอยากจะแสดงเป็นอาร์เรย์ numpy และทำคณิตศาสตร์ที่นั่นแล้วนำมันกลับไปที่อาร์ค

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 ข้อมูลโค้ดนี้มีไว้สำหรับอัปเดตค่าของเซลล์แรสเตอร์อย่างไรก็ตามจะแสดงพื้นฐานของการวนซ้ำ:

ฉันจะเพิ่มฟิลด์ใหม่ในตารางแอตทริบิวต์ raster และวนซ้ำได้อย่างไร

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. เลื่อนดูพจนานุกรมของคุณและแต่ละจุดจะจัดการกับ XYs ของเซลล์ 8 เซลล์โดยรอบ
  5. ดึงข้อมูลเหล่านี้จากพจนานุกรมของคุณและทดสอบด้วยกฎของคุณทันทีที่คุณพบค่าที่เป็นจริงคุณสามารถข้ามการทดสอบที่เหลือ
  6. เขียนผลลัพธ์ไปยังพจนานุกรมอื่นแล้วแปลงกลับเป็นกริดโดยสร้างจุด FeatureClass ขึ้นก่อนจากนั้นแปลงคะแนนเป็นกริด

2
ด้วยการแปลงเป็นชุดของคุณลักษณะจุดความคิดนี้จะกำจัดคุณสมบัติสองประการของการแสดงข้อมูลแบบ raster-based ที่ทำให้มันมีประสิทธิภาพมาก: (1) การค้นหาเพื่อนบ้านคือการดำเนินการเวลาคงที่ง่ายมากและ (2) เนื่องจากการจัดเก็บตำแหน่งที่ชัดเจน ไม่จำเป็นต้องใช้, RAM, ดิสก์และข้อกำหนด I / O มีน้อย ดังนั้นแม้ว่าวิธีนี้จะใช้ได้ แต่ก็ยากที่จะหาเหตุผลที่จะแนะนำ
whuber

ขอบคุณสำหรับคำตอบของคุณ Hornbydd ฉันตกลงกับการใช้วิธีการเช่นนี้ แต่ดูเหมือนว่าขั้นตอนที่ 4 และ 5 จะไม่เป็นการคำนวณที่มีประสิทธิภาพมากนัก แรสเตอร์ของฉันจะมีเซลล์ขั้นต่ำ 62,500 เซลล์ (ความละเอียดขั้นต่ำสำหรับแรสเตอร์ของฉันที่ฉันตั้งไว้คือ 250 เซลล์ x 250 เซลล์ แต่ความละเอียดสามารถและมักจะประกอบด้วยมากขึ้น) และฉันต้องทำแบบสอบถามเชิงพื้นที่ สำหรับทุกเงื่อนไขในการดำเนินการเปรียบเทียบของฉัน ... เนื่องจากฉันมี 6 เงื่อนไขนั่นจะเป็น 6 * 62500 = 375000 การสืบค้นเชิงพื้นที่ ฉันจะดีกว่าด้วยพีชคณิตแผนที่ แต่ขอบคุณสำหรับวิธีการใหม่ในการดูปัญหา upvoted
Conor

คุณไม่สามารถแปลงมันเป็น ASCII แล้วใช้โปรแกรมอย่าง R เพื่อทำการคำนวณหรือไม่?
Oliver Burdekin

บวกฉันมี Java แอปเพล็ฉันเขียนที่สามารถแก้ไขได้อย่างง่ายดายเพื่อตอบสนองเงื่อนไขของคุณข้างต้น มันเป็นเพียงอัลกอริธึมที่ทำให้เรียบ แต่การอัพเดตจะทำได้ง่ายมาก
Oliver Burdekin

ตราบใดที่โปรแกรมสามารถถูกเรียกใช้จากแพลตฟอร์ม. NET สำหรับผู้ใช้ที่ติดตั้ง. NET Framework 3.5 และ ArcGIS 10 เท่านั้น โปรแกรมนี้เป็นโอเพนซอร์ซและฉันต้องการให้เป็นข้อกำหนดซอฟต์แวร์เพียงอย่างเดียวเมื่อส่งมอบให้กับผู้ใช้ หากคำตอบของคุณสามารถนำไปใช้เพื่อตอบสนองความต้องการทั้งสองนี้ก็จะถือว่าเป็นคำตอบที่ถูกต้อง ฉันจะเพิ่มแท็กเวอร์ชันให้กับคำถามด้วยเพื่อความกระจ่าง
Conor

2

ทางออก:

ฉันแก้ไขมันก่อนหน้านี้ในวันนี้ รหัสคือการปรับวิธีการนี้ แนวคิดเบื้องหลังนี้ไม่ยากอย่างยิ่งเมื่อฉันคิดออกว่าวัตถุที่ใช้ในการติดต่อกับแรสเตอร์ทำอะไร วิธีการด้านล่างใช้ชุดข้อมูลสองชุด (inRasterDS และ outRasterDS) พวกเขาเป็นทั้งชุดข้อมูลเดียวกันฉันเพิ่งทำสำเนาของ inRasterDS และส่งผ่านมันเป็นเมธอด outRasterDS วิธีนี้พวกเขาทั้งสองมีขอบเขตเท่ากันการอ้างอิงเชิงพื้นที่ ฯลฯ วิธีการอ่านค่าจาก inRasterDS แต่ละเซลล์และทำการเปรียบเทียบเพื่อนบ้านที่ใกล้ที่สุด มันใช้ผลลัพธ์ของการเปรียบเทียบเหล่านั้นเป็นค่าที่เก็บไว้ใน outRasterDS

กระบวนการ:

ฉันใช้ IRasterCursor -> IPixelBlock -> SafeArray เพื่อรับค่าพิกเซลและ IRasterEdit เพื่อเขียนค่าใหม่ไปยัง raster เมื่อคุณสร้าง IPixelBlock คุณจะบอกขนาดและตำแหน่งของเครื่องที่คุณต้องการอ่าน / เขียน หากคุณต้องการแก้ไขเพียงครึ่งล่างของแรสเตอร์คุณตั้งค่านั้นเป็นพารามิเตอร์ IPixelBlock ของคุณ หากคุณต้องการวนซ้ำ raster ทั้งหมดคุณต้องตั้งค่า IPixelBlock ให้เท่ากับขนาดของ raster ทั้งหมด ฉันทำสิ่งนี้ในวิธีการด้านล่างโดยส่งผ่านขนาดไปยัง 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 สามารถอ่านได้สามวิธี:

  • โดยเซลล์ (ไม่มีประสิทธิภาพ);
  • ตามภาพ (ค่อนข้างมีประสิทธิภาพ);
  • โดยบล็อก (วิธีที่มีประสิทธิภาพที่สุด)

ฉันแนะนำให้อ่านภาพนิ่งที่กระจ่างแจ้งของ Chris Garrard

ดังนั้นวิธีที่มีประสิทธิภาพมากที่สุดคือการอ่านข้อมูลโดยบล็อกอย่างไรก็ตามสิ่งนี้จะทำให้ข้อมูลสูญหายในการติดต่อของพิกเซลที่อยู่เหนือขอบเขตบล็อกขณะที่ใช้ตัวกรอง ดังนั้นทางเลือกที่ปลอดภัยควรประกอบด้วยการอ่านภาพทั้งหมดในครั้งเดียวและใช้วิธีการแบบ numpy

ในด้านการคำนวณฉันควรใช้gdalfilter.pyและใช้แนวทาง VRT KernelFilteredSource โดยนัยเพื่อใช้ตัวกรองที่จำเป็นและเหนือสิ่งอื่นใดให้หลีกเลี่ยงการคำนวณจำนวนมาก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.