基于Azure目标检测结果的图片裁剪问题求助
问题:Azure Custom Vision目标检测后图片裁剪脚本错误排查
我在customvision.ai网站上拥有一个MS Azure目标检测模型,通过其API进行预测后,第一段PowerShell脚本可正常调用API并在图片中绘制出预测的边界框,但第二段使用相同坐标裁剪目标区域的脚本无法正确工作,裁剪出的是图片的其他部分,需要排查错误。
第一段可正常运行的脚本(预测并绘制边界框)
# First powershell script # API call to object detection model to predict objects and their bounding boxes $filePath = "C:\ImageOne.jpg" $fileBytes = [System.IO.File]::ReadAllBytes($FilePath); $Url = "<MyCustomVisionModelEndpoint>" $headers = @{ 'Prediction-Key' = $customVisionPredictionKey 'Content-Type' = 'application/octet-stream' } $proxy = [System.Net.WebRequest]::GetSystemWebProxy().GetProxy("https://<CustomVisionResourceName>.cognitiveservices.azure.com") $APIresult = Invoke-RestMethod -Method 'Post' -Uri $url -Body $fileBytes -Headers $headers -UseDefaultCredentials -Proxy $proxy -ProxyUseDefaultCredentials # Get Results and draw the predicted bounding boxes in the input image $results = $APIresult.predictions | Where-Object {!$_.tagName.toString().contains("not") -and !$_.tagName.toString().contains("door") -and !$_.tagName.toString().contains("tyre") -and $_.probability -ge 0.02} Add-Type -AssemblyName System.Drawing $srcImage=[System.Drawing.Image]::FromFile($FilePath) $height = $srcImage.height $width = $srcImage.width $graphics=[System.Drawing.Graphics]::FromImage($srcImage) $pen = New-Object Drawing.Pen([System.Drawing.Color]::Blue,3); $font = New-Object Drawing.Font("Arial", 7); $brush = New-Object Drawing.SolidBrush([System.Drawing.Color]::Red); foreach($result in $results) { $left = $width * $result.boundingBox.left $top = $height * $result.boundingBox.top $PHeight = $height * $result.boundingBox.height $PWidth = $width * $result.boundingBox.width $rect = New-Object Drawing.Rectangle($left, $top, $PWidth, $PHeight); $graphics.DrawRectangle($pen, $rect); $tag = "Tag: " + $result.tagName + " ,Probability: " + [math]::Round($result.probability * 100,2) $graphics.DrawString($tag,$font,$brush,$left, $top); } $graphics.Dispose() if($results) { $srcImage.Save("D:\Output.jpg") }
第二段存在问题的裁剪脚本
# Second powershell script Add-Type -AssemblyName System.Drawing $filepath = "C:\ImageOne.jpg" $srcImage=[System.Drawing.Image]::FromFile($FilePath) $srcRect = New-Object Drawing.Rectangle(0,0,$srcImage.Width,$srcImage.Height) # Here left, top, width, height co-ordinates comes from above powershell code which does predictions and draws rectangular bounding boxes $destRect = New-Object Drawing.Rectangle([UInt32]($left),[UInt32]($top),[UInt32]($PWidth),[UInt32]($PHeight)) $bmp=new-object System.Drawing.Bitmap($destRect.Width,$destRect.Height) $graphics=[System.Drawing.Graphics]::FromImage($bmp) # I tried with [System.Drawing.GraphicsUnit]::Pixel also, but no use $units = [System.Drawing.GraphicsUnit]::Point $destRect = new-object Drawing.Rectangle($destRect.Left, $destRect.Top, $destRect.Width, $destRect.Height) $srcRect = new-object Drawing.Rectangle($srcRect.Left, $srcRect.Top, $srcRect.Width, $srcRect.Height) $graphics.DrawImage($srcImage, $srcRect, $destRect, $units) $graphics.Dispose() $bmp.Save("D:\test.jpg")
错误原因分析
DrawImage参数顺序错误:你使用的DrawImage重载(DrawImage(Image, Rectangle, Rectangle, GraphicsUnit))中,第二个参数是目标画布上的绘制区域,第三个参数才是源图像中要裁剪的区域。你当前把源区域和目标区域的参数顺序搞反了,导致裁剪的区域完全错误。- 多余的Rect重复创建:脚本中重复创建
srcRect和destRect的代码没有意义,反而可能引入变量异常。 - 不必要的类型强制转换:将坐标强制转换为
[UInt32]可能导致小数坐标被错误截断,而第一段脚本中直接使用计算后的数值创建Rectangle(其构造函数接受int类型,会自动进行合理的转换)。 - 变量传递风险:如果单独运行第二段脚本,
$left、$top等变量未定义,会默认取0值,导致裁剪左上角区域。
修正后的裁剪脚本
如果是和第一段脚本结合运行(确保$left、$top、$PWidth、$PHeight已正确计算),修正后的脚本如下:
# 修正后的裁剪脚本(需在第一段脚本之后运行,或确保坐标变量已正确赋值) Add-Type -AssemblyName System.Drawing $filepath = "C:\ImageOne.jpg" $srcImage = [System.Drawing.Image]::FromFile($FilePath) # 使用第一段脚本中计算好的边界框坐标 $cropRect = New-Object Drawing.Rectangle([int]$left, [int]$top, [int]$PWidth, [int]$PHeight) # 创建对应裁剪尺寸的位图 $croppedBmp = New-Object System.Drawing.Bitmap($cropRect.Width, $cropRect.Height) $graphics = [System.Drawing.Graphics]::FromImage($croppedBmp) # 正确调用DrawImage:目标区域是(0,0,裁剪宽,裁剪高),源区域是要裁剪的Rect $graphics.DrawImage($srcImage, (New-Object Drawing.Rectangle(0, 0, $cropRect.Width, $cropRect.Height)), $cropRect, [System.Drawing.GraphicsUnit]::Pixel ) # 释放资源 $graphics.Dispose() $srcImage.Dispose() $croppedBmp.Save("D:\test.jpg") $croppedBmp.Dispose()
如果需要单独运行裁剪脚本,需要先完成API预测并计算坐标,完整整合版脚本可以将两段逻辑合并,避免变量传递问题。
内容的提问来源于stack exchange,提问作者Surya
相关产品推荐
相关产品推荐

