最佳的去除边框/裁剪图像的方法

huangapple go评论71阅读模式
英文:

Best way to remove borders / crop image

问题

我正在使用一个Go包(Go绑定到ImageMagick的MagickWand C API)来处理ImageMagick,我正在从图像中删除边框(裁剪)。我使用的trim函数的用法如下所示。

现在的问题是模糊因子。例如,如果我将值设置为2000,图像(源图像在这里)仍然有一些白色图像,如下所示:

  • 模糊因子值2000 --> 结果
  • 模糊因子值10000 --> 结果

我创建了一个小的HTML文件来说明问题。它包含了两个图像:https://dl.dropboxusercontent.com/u/15684927/image-trim-problem.html

正如你所看到的,源图像在右下角有一些像素导致了问题。如果我将因子设置为10000,我担心会丢失其他图片上的像素。如果我将其设置为2000,在这样的图片上裁剪就不正确。

所以我的实际问题是:最佳的“裁剪”/“修剪”图像的方法是什么?

package main

import "gopkg.in/gographics/imagick.v1/imagick"

func main() {
	imagick.Initialize()
	defer imagick.Terminate()

	inputFile := "tshirt-original.jpg"
	outputFile := "trimmed.jpg"
	mw := imagick.NewMagickWand()
	// Schedule cleanup
	defer mw.Destroy()

	// read image
	err := mw.ReadImage(inputFile)
	if err != nil {
		panic(err)
	}

	// first trim original image
	// fuzz: by default target must match a particular pixel color exactly.
	// However, in many cases two colors may differ by a small amount. The fuzz
	// member of image defines how much tolerance is acceptable to consider two
	// colors as the same. For example, set fuzz to 10 and the color red at
	// intensities of 100 and 102 respectively are now interpreted as the same
	// color for the purposes of the floodfill.
	mw.TrimImage(10000)

	// Set the compression quality to 95 (high quality = low compression)
	err = mw.SetImageCompressionQuality(95)
	if err != nil {
		panic(err)
	}

	// save
	err = mw.WriteImage(outputFile)
	if err != nil {
		panic(err)
	}
}
英文:

I am using a Go package (Go binding to ImageMagick's MagickWand C API) to ImageMagick where I'm removing borders from images (cropping). The way I am using the trim function can be found below.

Now the problem is the fuzzy factor. For example, if I set the value to 2000, the image (here is the source) still has some white images like these:

  • fuzz factor value 2000 --> result
  • fuzz factor value 10000 --> result

I have created a small html which illustrates the problem best. It contains both images: https://dl.dropboxusercontent.com/u/15684927/image-trim-problem.html

As you can see the source has some pixels on the bottom right corner which are causing the trouble. If I set the factor to 10000, I'm afraid that I will loose pixels on other pictures. If I set it on 2000, the trimming isn't done right in pictures like these.

So my actual question is: what is the best way to "crop" / "trim" images?

package main

import "gopkg.in/gographics/imagick.v1/imagick"

func main() {
	imagick.Initialize()
	defer imagick.Terminate()

	inputFile := "tshirt-original.jpg"
	outputFile := "trimmed.jpg"
	mw := imagick.NewMagickWand()
	// Schedule cleanup
	defer mw.Destroy()

	// read image
	err := mw.ReadImage(inputFile)
	if err != nil {
		panic(err)
	}

	// first trim original image
	// fuzz: by default target must match a particular pixel color exactly.
	// However, in many cases two colors may differ by a small amount. The fuzz
	// member of image defines how much tolerance is acceptable to consider two
	// colors as the same. For example, set fuzz to 10 and the color red at
	// intensities of 100 and 102 respectively are now interpreted as the same
	// color for the purposes of the floodfill.
	mw.TrimImage(10000)

	// Set the compression quality to 95 (high quality = low compression)
	err = mw.SetImageCompressionQuality(95)
	if err != nil {
		panic(err)
	}

	// save
	err = mw.WriteImage(outputFile)
	if err != nil {
		panic(err)
	}
}

答案1

得分: 7

基本上,你的问题是在图像边缘有一个高频率、高振幅的伪影。换句话说,边缘处有一个尖锐、高峰的部分,如果你想使用修剪功能,就必须使用一个很高的模糊值来克服这个问题,这样算法也会将“实际内容”视为“背景”(边框)。

解决方案之一是使用多步骤的方法,首先平滑边缘伪影,然后对结果图像应用修剪。通过平滑处理,你可以消除高峰并将其变成一个漂亮的连续山丘。而连续山丘可以使用较低的模糊值轻松修剪。然后,你可以使用修剪后的几何形状来裁剪原始图像。

具体来说,让我们以原始图像为例:
最佳的去除边框/裁剪图像的方法

现在,让我们使用模糊半径为10、sigma为10的模糊处理来平滑边缘,通过命令convert original.jpg -blur 10x10 10x10.jpg,得到:
最佳的去除边框/裁剪图像的方法

现在,你可能会注意到边缘上的伪影几乎消失了。

我们现在可以进行“虚拟”修剪,并通过命令convert 10x10.jpg -fuzz 2000 -format %@ info:询问ImageMagick修剪的结果,根据文档,这将给出“修剪边界框(实际上不进行修剪)”:1326x1560+357+578%

使用这些值(除了百分号)作为裁剪几何形状,得到裁剪命令convert original.jpg -crop 1326x1560+357+578 cropped.jpg,得到:

最佳的去除边框/裁剪图像的方法

编辑:

现在,由于你想要代码,使用imagick,以下是代码解决方案。它假设文件存储为'./data/original.jpg',并将其存储为'./data/trimmed.jpg'。

package main

import (
  "fmt"

  "gopkg.in/gographics/imagick.v2/imagick"
)

func init() {
  imagick.Initialize()
}

const originalImageFilename = "data/original.jpg"

func main() {

  mw := imagick.NewMagickWand()
  err := mw.ReadImage(originalImageFilename)
  if err != nil {
    fmt.Sprint(err.Error())
    return
  }

  // Use a clone to determine what will happen
  mw2 := mw.Clone()

  mw2.BlurImage(10, 10)
  mw2.TrimImage(2000)

  _, _, xOffset, yOffset, err := mw2.GetImagePage()
  if err != nil {
    fmt.Sprint(err.Error())
    return
  }

  trimmedWidth := mw2.GetImageWidth()
  trimmedHeight := mw2.GetImageHeight()

  mw2.Destroy()

  mw.CropImage(trimmedWidth, trimmedHeight, xOffset, yOffset)

  mw.WriteImage("data/trimmed.jpg")
  mw.Destroy()
}
英文:

Basically, your problem is that you have a high-frequency, high-amplitude artifact at the edge of your image. Or, put differently, a sharp, high peak at the edge, which, if you want to use trim, forces you to use such a high a fuzz-value to overcome this, that the algorithm also considers the 'actual content' as equal to the 'background' (border).

One solution here is to use a multi-step approach, whereby you first smooth out the edge artifacts and then apply trim to the resulting image. By smoothing it out, you get rid of the high peak and smear it out into a nice rolling hill. Rolling hills, in turn, can be easily trimmed with low fuzz values. This then provides you with the desired geometry which you can use to crop the original.

Specifically, let's take the original image:
最佳的去除边框/裁剪图像的方法

Now, let's smooth out that ridge on the edge using a blur with a radius of 10 and a sigma of 10 through convert original.jpg -blur 10x10 10x10.jpg, which yields:
最佳的去除边框/裁剪图像的方法

Now, you might notice that the artifacts on the edge have now pretty much disappeared.

We can now do a 'virtual' trim and ask ImageMagick what the result of the trim would be through convert 10x10.jpg -fuzz 2000 -format %@ info:, which, according to the documentation gives you the "trim bounding box (without actually trimming)": 1326x1560+357+578%

Taking these values (except for the percentage sign) and using them for crop geometry, gives you the convert with crop command convert original.jpg -crop 1326x1560+357+578 cropped.jpg, which gives you:

最佳的去除边框/裁剪图像的方法

Edit:

Now, since you want this as code, using imagick, here's the solution in code. It assumes you have the file stored as './data/original.jpg' and will store it as './data/trimmed.jpg'

<!-- language: lang-go -->

package main

import (
  &quot;fmt&quot;

  &quot;gopkg.in/gographics/imagick.v2/imagick&quot;
)

func init() {
  imagick.Initialize()
}

const originalImageFilename = &quot;data/original.jpg&quot;

func main() {

  mw := imagick.NewMagickWand()
  err := mw.ReadImage(originalImageFilename)
  if err != nil {
    fmt.Sprint(err.Error())
    return
  }

  // Use a clone to determine what will happen
  mw2 := mw.Clone()

  mw2.BlurImage(10, 10)
  mw2.TrimImage(2000)

  _, _, xOffset, yOffset, err := mw2.GetImagePage()
  if err != nil {
    fmt.Sprint(err.Error())
    return
  }

  trimmedWidth := mw2.GetImageWidth()
  trimmedHeight := mw2.GetImageHeight()

  mw2.Destroy()

  mw.CropImage(trimmedWidth, trimmedHeight, xOffset, yOffset)

  mw.WriteImage(&quot;data/trimmed.jpg&quot;)
  mw.Destroy()
}

4: https://godoc.org/gopkg.in/gographics/imagick.v2/imagick "imagick"

huangapple
  • 本文由 发表于 2016年4月6日 17:17:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/36446678.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定