【问题标题】:Use PowerShell to extract GPS Latitude etc. (Properties > Details) from an image file使用 PowerShell 从图像文件中提取 GPS 纬度等(属性 > 详细信息)
【发布时间】:2021-10-28 10:36:45
【问题描述】:

我正在寻找一种从大量 .jpg 文件中提取 GPS 纬度和经度值的方法。

我知道 Exiftool 可以做到这一点,但是由于我所追求的值在该文件的 Windows 10 资源管理器中可见(属性 > 详细信息 > GPS 航向 > 纬度)...我可以使用 PS 直接抓住他们?我假设这样会更快。

我知道如何提取$img.FullName 等,但无法通过这种方式进入纬度。

【问题讨论】:

  • 看看各种 dotnet ExIf 库。此外,您可以通过 Windows 扩展文件元数据结构获取该对话框中显示的数据。确切的 ID 号可能会有所不同,具体取决于将任何给定文件的处理程序添加到您的 Windows 安装的时间。这是获取 id 到字段映射的蛮力方法 ... >>> 函数 Get-AvailableExtendedFilePropertyTable - Pastebin.com — pastebin.com/YmKCZb1K
  • Exiftool 可以很好地解决这个问题,甚至可以选择以 json 格式输出数据,您可以轻松使用 ConvertFrom-Json cmdlet 将其转换为对象。

标签: powershell gps jpeg exif


【解决方案1】:

要在不使用外部工具的情况下访问您在 Windows 资源管理器中看到的元数据(不同于文件系统元数据),您必须使用 Windows Image Acquisition (WIA) Automation Layer。你可以这样做:

# Create an ImageFile object and load an image file
$image = New-Object -ComObject Wia.ImageFile
$image.LoadFile("C:\Absolute\path\to\my.jpg")

# Read your desirered metadata
$image.Properties.Item('GpsLatitude').Value
$image.Properties.Item('GpsLongitude').Value

请注意,与 ExifToolexiv2 等外部工具相比,WIA 的解析能力有限。但这足以获得您需要的数据。

您可以阅读更多关于ImageFile 对象以及here 的功能。

【讨论】:

    【解决方案2】:

    感谢大家,尤其是@stackprotector。我学到了很多东西,并设法弄清楚如何提取我的确切值,包括重要的 N、S、E、W。

    为了帮助他人,以下是我的发现:

    # Based on answer from @stackprotector (above)
    # Create an ImageFile object and load an image file
    $image = New-Object -ComObject Wia.ImageFile
    $image.LoadFile("D:\temp\toNAS\temp\PXL_20210830_004210948.jpg")
    $image.Properties.Item('GpsLatitudeRef').Value
    # S
    $image.Properties.Item('GpsLatitude').Value 
    <#
    Value Numerator Denominator
    ----- --------- -----------
       37        37           1
       51        51           1
    43.92      4392         100
    >#
    # Can rinse and repeat for GpsLongitude
    

    现在提取我想要的。这是一个子集;很容易在 GpsLongitude 中复制另一个 :-)

    $image.Properties.Item('GpsLatitude').Value[1].Value
    # 37
    
     $image.Properties.Item('GpsLatitude').Value[2].Value
    # 51
    
    $image.Properties.Item('GpsLatitude').Value[3].Value
    # 43.92
    
    $image.Properties.Item('GpsLatitudeRef').Value 
    # S
    
    $image.Properties.Item('DateTime').Value
    # 2021:08:30 10:42:10
    # This is local not UTC
    
    # So final latitude is 37 deg  51 min 43.92 sec S 
    # Taken on 2021:08:30 10:42:10 local time
    
    

    相机内的值显示为 -37.8622,拍摄于 2021 年 8 月 30 日当地时间 10:42:10,对此非常满意,包括南方的“-”

    我会试试 Exiftool @daniel 看看它是否更容易。我以前用过,很好用。

    更新 (2022-02-13)。 我最终选择了 Exiftool。随着我对 JSON 越来越有信心,该工具集对我来说变得更加明显。这是代码的关键sn-ps(如下)。一件小事:这个 exiftool 选项集在运行时没有给出“反馈”。只在最后给出了总结:

    # $photoYear is the root folder with the images
    $data = (exiftool -if '$gpsdatetime' -s -s -s -json -ext jpg -filename -FileTypeExtension -Directory -CreateDate -GPSDateTime -GPSLatitude -GPSLongitude -n -r $photoYear ) | ConvertFrom-Json
    # ...
    [int]$n = 0
    foreach ($photo in $data){
        Write-host $n, "  " $photo.CreateDate,  $photo.GPSLatitude, $photo.GPSLongitude
        $n++
        }
    

    【讨论】:

      【解决方案3】:

      使用@dwids 答案和@stackprotector 答案,我想出了以下方法来遍历文件夹中的所有文件。这不是最整洁的,但它是不言自明的:

      cls
      
      $FolderPath = "c:\MyFolder"
      
      Get-ChildItem $FolderPath -Filter *.* | where { ! $_.PSIsContainer } | 
      Foreach-Object {
          # Get the file name and path, write it out to screen
          $FileName = $_.FullName
          Write-Host "$FileName"
      
          # Create an ImageFile object and load an image file
          $image = New-Object -ComObject Wia.ImageFile
          $image.LoadFile($FileName)
      
          # Read your desirered metadata, if it doesn't contain any, say NONE
          try
          {
              #Clear variables for Lat and Lon
              Clear-Variable Lat*
              Clear-Variable Lon*
              $LatDEG = $image.Properties.Item('GpsLatitude').Value[1].Value
              $LatMIN = $image.Properties.Item('GpsLatitude').Value[2].Value
              $LatSEC = $image.Properties.Item('GpsLatitude').Value[3].Value 
              $LatREF = $image.Properties.Item('GpsLatitudeRef').Value
              $LonDEG = $image.Properties.Item('GpsLongitude').Value[1].Value
              $LonMIN = $image.Properties.Item('GpsLongitude').Value[2].Value
              $LonSEC = $image.Properties.Item('GpsLongitude').Value[3].Value 
              $LonREF = $image.Properties.Item('GpsLongitudeRef').Value
      
              # Convert them to Degrees Minutes Seconds Ref
              $LatSTR = "$LatDEG$([char]176) $LatMIN$([char]39) $LatSEC$([char]34) $LatREF"
              $LonSTR = "$LonDEG$([char]176) $LonMIN$([char]39) $LonSEC$([char]34) $LonREF"
      
              # Write the full coordinates out
              Write-Host "$LatSTR $LonSTR"
          }
          catch
          {
              Write-Host "NONE"
          }
      }
      

      如果您只需要坐标列表,显然可以删除 Write-Host "$FileName"

      您可以将其更改为Write-Host "$_" 以仅列出文件名

      您可以将-Recurse 添加到et-ChildItem $FolderPath -Filter *.* |et-ChildItem $FolderPath -Filter *.* -Recurse | 以查看所有子文件夹中的所有文件

      【讨论】:

      • 优秀。你的帖子提醒我更新原来的回复
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多