Raster diff: วิธีตรวจสอบว่าภาพมีค่าเหมือนกันหรือไม่?


10

มีวิธีตรวจสอบเพื่อดูว่าเลเยอร์แรสเตอร์ที่กำหนด 2 รายการมีเนื้อหาเหมือนกันหรือไม่?

เรามีปัญหาเกี่ยวกับปริมาณพื้นที่เก็บข้อมูลที่ใช้ร่วมกันในองค์กรของเรา: ขณะนี้มีขนาดใหญ่มากซึ่งใช้เวลามากกว่า 3 วันในการสำรองข้อมูลเต็มรูปแบบ การตรวจสอบเบื้องต้นพบว่าหนึ่งในผู้ร้ายที่กินพื้นที่มากที่สุดคือเปิด / ปิดแรสเตอร์ที่ควรเก็บเป็นเลเยอร์ 1 บิตด้วยการบีบอัด CCITT

แรสเตอร์ทั่วไป / ปัจจุบัน - ไม่ใช่ปัจจุบัน

อิมเมจตัวอย่างนี้เป็น 2 บิตในปัจจุบัน (ดังนั้นค่าที่เป็นไปได้ 3 ค่า) และบันทึกเป็นไฟล์บีบอัด LZW ขนาด 11 MB ในระบบไฟล์ หลังจากแปลงเป็น 1 บิต (เพื่อให้มี 2 ค่าที่เป็นไปได้) และใช้การบีบอัด CCITT Group 4 เราได้รับการลดลงเหลือ 1.3 MB เกือบเต็มตามลำดับความสำคัญของการออม

(อันที่จริงแล้วเป็นพลเมืองที่ประพฤติตัวดีมีคนอื่นเก็บไว้เป็น 32 บิตลอย!)

นี่เป็นข่าวที่น่าอัศจรรย์! อย่างไรก็ตามมีเกือบ 7,000 ภาพที่จะใช้เช่นกัน มันจะตรงไปตรงมาในการเขียนสคริปต์เพื่อบีบอัดพวกเขา:

for old_img in [list of images]:
    convert_to_1bit_and_compress(old_img)
    remove(old_img)
    replace_with_new(old_img, new_img)

... แต่มันขาดการทดสอบที่สำคัญ: เป็นรุ่นเนื้อหาบีบอัดใหม่เหมือนกันหรือไม่

  if raster_diff(old_img, new_img) == "Identical":
      remove(old_img)
      rename(new_img, old_img)

มีเครื่องมือหรือวิธีการที่สามารถ (dis) พิสูจน์ได้โดยอัตโนมัติว่าเนื้อหาของ Image-A นั้นมีคุณค่าเหมือนกันกับเนื้อหาของ Image-B หรือไม่?

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

ผลลัพธ์ที่แย่มาก

อัปเดต:ผู้กระทำผิดที่ใหญ่ที่สุดคือ 32 บิตลอยตัวในช่วงที่สูงถึง 100,000px ข้างหนึ่งดังนั้น ~ 30GB ที่ไม่บีบอัด


1
วิธีหนึ่งที่จะนำไปใช้raster_diff(old_img, new_img) == "Identical"คือการตรวจสอบว่าค่าสูงสุดของค่าสัมบูรณ์ของความแตกต่างเท่ากับ 0 โดยที่พื้นที่ถูกยึดครองในขอบเขตกริดทั้งหมด นี่เป็นวิธีแก้ปัญหาที่คุณกำลังมองหาใช่ไหม (ถ้าเป็นเช่นนั้นจะต้องได้รับการปรับปรุงเพื่อตรวจสอบว่าค่า NoData ใด ๆ มีความสอดคล้องเช่นกัน)
whuber

1
@whuber ขอบคุณสำหรับการNoDataจัดการที่เหมาะสมให้อยู่ในการสนทนา
matt wilkie

หากคุณสามารถตรวจสอบได้len(numpy.unique(yourraster)) == 2คุณจะรู้ว่ามีค่าที่ไม่ซ้ำกัน 2 ค่าและคุณสามารถทำสิ่งนี้ได้อย่างปลอดภัย
RemcoGerlich

@Remco อัลกอริทึมพื้นฐานnumpy.uniqueจะมีราคาแพงมากขึ้น (ทั้งในแง่ของเวลาและพื้นที่) มากกว่าวิธีอื่น ๆ ส่วนใหญ่ในการตรวจสอบว่าความแตกต่างนั้นคงที่ เมื่อเผชิญหน้ากับความแตกต่างระหว่าง rasters จุดลอยตัวขนาดใหญ่สองตัวที่แสดงความแตกต่างมากมาย (เช่นการเปรียบเทียบแบบดั้งเดิมกับรุ่นบีบอัดแบบสูญเสีย) มันน่าจะชะงักลงตลอดไปหรือล้มเหลวอย่างสมบูรณ์
whuber

1
@ Aaron ฉันถูกดึงออกจากโครงการเพื่อทำสิ่งอื่น ส่วนหนึ่งเป็นเพราะเวลาในการพัฒนาเพิ่มขึ้นเรื่อย ๆ : มีกรณีขอบจำนวนมากเกินกว่าที่จะจัดการโดยอัตโนมัติดังนั้นการตัดสินใจจึงทำให้ปัญหาเกิดขึ้นกับผู้คนที่สร้างภาพแทนที่จะแก้ไขได้ (เช่น "โควต้าดิสก์ของคุณคือ X คุณเรียนรู้วิธีทำงานกับมัน") อย่างไรก็ตามgdalcompare.pyมีคำสัญญาที่ยอดเยี่ยม ( ดูคำตอบ )
matt wilkie

คำตอบ:


8

ลองแปลงแรสเตอร์ของคุณให้เป็นอาร์เรย์แบบ numpy แล้วตรวจสอบดูว่ามีรูปร่างและองค์ประกอบเดียวกันกับarray_equalหรือไม่ หากเหมือนกันผลลัพธ์ควรเป็นTrue:

ArcGIS:

import arcpy, numpy

raster1 = r'C:\path\to\raster.tif'
raster2 = r'C:\path\to\raster.tif'

r1 = arcpy.RasterToNumPyArray(raster1)
r2 = arcpy.RasterToNumPyArray(raster2)

d = numpy.array_equal(r1,r2)

if d == False:
    print "They differ"

else:
    print "They are the same"

GDAL:

import numpy
from osgeo import gdal        

raster1 = r'C:\path\to\raster.tif'
raster2 = r'C:\path\to\raster.tif'

ds1 = gdal.Open(raster1)
ds2 = gdal.Open(raster2)

r1 = numpy.array(ds1.ReadAsArray())
r2 = numpy.array(ds2.ReadAsArray())

d = numpy.array_equal(r1,r2)

if d == False:
    print "They differ"

else:
    print "They are the same"

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

1
คะแนนที่ดี @whuber ฉันทำการปรับเปลี่ยนอย่างรวดเร็วสำหรับสคริปต์ที่ควรคำนึงถึงรูปร่างและองค์ประกอบ ฉันจะตรวจสอบคะแนนที่คุณนำมาและรายงานผลการวิจัย
แอรอน

1
@whuber เกี่ยวกับการNoDataจัดการRasterToNumPyArrayกำหนดโดยค่า NoData ของ raster อินพุตให้กับอาร์เรย์ ผู้ใช้สามารถระบุค่าที่แตกต่างแม้ว่ามันจะไม่ใช้ในกรณีของแมตต์ เกี่ยวกับความเร็วนั้นสคริปต์ใช้เวลา 4.5 วินาทีในการเปรียบเทียบแรสเตอร์ 2 4 บิต 2 รายการกับ 6210 คอลัมน์และ 7650 แถว (ขอบเขต DOQQ) ฉันยังไม่ได้เปรียบเทียบวิธีการกับสรุปใด ๆ
แอรอน

1
ฉันพับเก็บใน gdal เทียบเท่าดัดแปลงมาจากgis.stackexchange.com/questions/32995/…
matt wilkie

4

คุณสามารถมีลองกับสคริปต์ gdalcompare.py http://www.gdal.org/gdalcompare.html ซอร์สโค้ดของสคริปต์อยู่ที่http://trac.osgeo.org/gdal/browser/trunk/gdal/swig/python/scripts/gdalcompare.pyและเนื่องจากเป็นสคริปต์ไพ ธ จึงควรลบสิ่งที่ไม่จำเป็นออกได้ง่าย ทดสอบและเพิ่มรายการใหม่เพื่อให้เหมาะกับความต้องการในปัจจุบันของคุณ สคริปต์ดูเหมือนว่าจะทำการเปรียบเทียบแบบพิกเซลต่อพิกเซลโดยการอ่านข้อมูลภาพจากวงภาพสองภาพต่อวงและนั่นอาจเป็นวิธีที่ค่อนข้างรวดเร็วและสามารถนำมาใช้ซ้ำได้


1
ที่รักฉันรัก gdal ไม่รู้เกี่ยวกับสคริปต์นี้ เอกสารสำหรับการตีความผลลัพธ์นั้นกระจัดกระจายเป็นไม่มีอยู่แม้ว่า ;-) ในการทดสอบครั้งแรกของฉันจะรายงานความแตกต่างในการตีความสีและพาเลทซึ่งหมายความว่ามันอาจเฉพาะเจาะจงมากเกินไปสำหรับความต้องการในปัจจุบันของฉัน ฉันยังคงสำรวจมันอยู่ (หมายเหตุ: คำตอบนี้สั้นเกินไปที่จะเป็นแบบที่ดีที่นี่ลิงค์เฉพาะคำตอบที่หมดกำลังใจโปรดพิจารณาอย่างรอบคอบ)
matt wilkie

1

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


สิ่งนี้จะใช้กับการลอยแบบ 32 บิตหรือไม่? การสร้างและเปรียบเทียบสองตารางจริง ๆ จะเร็วกว่า (หรือง่ายกว่า) มากกว่าการตรวจสอบค่าความแตกต่างของแรสเตอร์ทั้งสอง (ซึ่งโดยหลักการแล้วควรเป็นศูนย์และไม่มีข้อมูล)
whuber

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

@radouxju ภาพอยู่ที่ด้านข้างสูงสุดถึง 100,000px ดังนั้นจึงไม่มีการบีบอัด ~ 30GB เราไม่มีเครื่องจักรที่มี ram มากขนาดนั้น (แม้ว่าอาจเป็นเสมือน ... )
matt wilkie

ดูเหมือนว่า RAM จะไม่เป็นปัญหาหากคุณใช้ ArcGIS เนทีฟ ค่อนข้างดีสำหรับการใช้ RAM เมื่อประมวลผลกริด: ภายในสามารถทำการประมวลผลแบบทีละแถวตามกลุ่มของแถวและตามหน้าต่างสี่เหลี่ยม การดำเนินการในท้องถิ่นเช่นการลบตารางหนึ่งจากอีกตารางหนึ่งสามารถทำงานได้ที่ความเร็วของอินพุตและเอาต์พุตซึ่งต้องการบัฟเฟอร์เพียงหนึ่ง (ค่อนข้างเล็ก) สำหรับชุดข้อมูลแต่ละชุด การสร้างตารางคุณลักษณะต้องมีตารางแฮชเพิ่มเติม - ซึ่งอาจเป็นขนาดจิ๋วเมื่อมีค่าเพียงหนึ่งหรือสองค่าปรากฏขึ้น แต่อาจมีขนาดใหญ่มากสำหรับกริดแบบสุ่ม
whuber

numpy จะทำการสลับกับอาเรย์ 2 * 30Go จำนวนมากนี่ไม่ใช่ ArcGIS อีกต่อไป ฉันสันนิษฐานจากหน้าจอพิมพ์ว่าภาพเป็นภาพที่จัดเรียง (ส่วนใหญ่มีค่าเพียงเล็กน้อยเท่านั้น) ดังนั้นคุณจึงไม่คาดว่าจะมีคลาสมาก
radouxju

0

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

mean_obj = arcpy.GetRasterProperties(input_raster, 'MEAN')
mean = float(mean_obj.getOutput(0))
if round(mean, 4) != 0.2010:
    print("raster differs from expected mean.")

std_obj = arcpy.GetRasterProperties(input_raster, 'STD')
std = float(std_obj.getOutput(0))
if round(std, 4) != 0.0161:
    print("raster differs from expected standard deviation.")

2
หนึ่งใหญ่วิธีการหลอกสถิติเหล่านี้จะเปลี่ยนรูปเนื้อหาของเซลล์ (ซึ่งสามารถเกิดขึ้นได้และไม่เมื่อขนาดของภาพไม่ได้ค่อนข้างขวา) ใน rasters ที่มีขนาดใหญ่มากทั้ง SD และค่าเฉลี่ยนั้นจะตรวจจับการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ ที่กระจัดกระจายได้อย่างน่าเชื่อถือ น่าจะเป็นไปได้ว่าพวกเขาจะไม่ตรวจพบการส่งตัวอย่างตารางใหม่เช่นกันหากใช้การบิดแบบลูกบาศก์ (ซึ่งมีจุดประสงค์เพื่อรักษาค่าเฉลี่ยและ SD) ดูเหมือนจะรอบคอบแทนที่จะเปรียบเทียบ SD ของความแตกต่างของกริดกับศูนย์
whuber

0

วิธีที่ง่ายที่สุดคือการลบแรสเตอร์หนึ่งอันจากอีกอันหากผลลัพธ์คือ 0 ภาพทั้งคู่จะเหมือนกัน นอกจากนี้คุณสามารถดูฮิสโตแกรมหรือพล็อตตามสีผลลัพธ์


การลบดูเหมือนเป็นวิธีที่ดีในการทำการเปรียบเทียบ อย่างไรก็ตามฉันเชื่อว่าฮิสโตแกรมจะไม่เป็นประโยชน์ในการตรวจสอบปัญหาเกี่ยวกับค่า NoData ตัวอย่างเช่นสมมติว่าขั้นตอนการบีบอัดกำจัดเส้นขอบหนึ่งพิกเซลรอบ ๆ ตาราง (อาจเกิดขึ้นได้!) แต่อย่างอื่นก็แม่นยำ: ความแตกต่างทั้งหมดจะยังคงเป็นศูนย์ นอกจากนี้คุณยังสังเกตเห็นว่า OP ต้องการทำเช่นนี้กับชุดข้อมูลแรสเตอร์ 7000 ชุดหรือไม่ ฉันไม่แน่ใจว่าเขาจะเพลิดเพลินกับการตรวจสอบ 7000 แปลง
whuber
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.