在 JPEG 图像上画一条简单的线
Posted
技术标签:
【中文标题】在 JPEG 图像上画一条简单的线【英文标题】:Drawing a simple line on a JPEG image 【发布时间】:2017-12-29 19:54:56 【问题描述】:我又被一个看似简单的问题困住了。
我将 JPEG 文件加载到 CGImage 中。我得到了正确的宽度和高度值(以像素为单位),并且能够在 ImageView 控制器中显示“myImage”。但我想在这张图片上添加一些图形,发现我应该把它放到一个 NSImage 中。所以我做了,但得到了不同的(比例)宽度和高度值:595.08 代替 1653,841.68 代替 2338。
我试图从 CGContext 'gc' 创建一个 NSCGContext 用于绘制(一条简单的线和一个矩形),结果是“可选类型 'CGContext 的值?'没有打开,你的意思是用'!'还是'?'?”...我迷路了...
// with NSData
//
let imageAsData = try Data(contentsOf: chosenFiles[0])
let imageProvider = CGDataProvider(data: imageAsData as CFData)
var myImage = CGImage(jpegDataProviderSource: imageProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
let imageWidth = myImage!.width
let imageHeight = myImage!.height
// with NSImage, now
//
let imageAsNSImage=NSImage(contentsOf: chosenFiles[0])
let imageSize=imageAsNSImage?.size // ---> 0.36 * pixels
// creating a CG context and drawing
//
let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
let gc = CGContext(data: nil, width: imageWidth, height: imageHeight, bitsPerComponent: 8, bytesPerRow: 0,space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)
let NSGContext = NSGraphicsContext(cgContext: gc, flipped: true)
let currentContext = NSGraphicsContext.current() // Cocoa GC object appropriate for the current drawing environment
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current = NSGContext
NSGContext?.beginPath()
NSGContext?.setStrokeColor(redColor)
NSGContext?.setLineWidth(50.0)
NSGContext?.move(to: targetStart)
NSGContext?.addLine(to: targetEnd)
NSGContext?.setStrokeColor(grayColor)
NSGContext?.setFillColor(grayColor)
NSGContext?.addRect(ROIRect)
NSGContext?.closePath()
NSGContext.restoreGraphicsState()
imageAsNSImage?.draw(at: NSZeroPoint, from: NSZeroRect, operation: NSCompositeSourceOver, fraction: 1.0)
imageAsNSImage?.unlockFocus()
NSGraphicsContext.setcurrent(currentContext)
myImageView.image = imageAsNSImage // image & drawings should show in View
【问题讨论】:
没有人知道你在哪个类下编写代码。你创建一个 CGImage 对象是为了什么目的? 我创建了一个 CGImage 以便以后访问像素(此处未显示)。我需要使用概率霍夫变换来检测 ROI(感兴趣区域)内的一条线,它已经或多或少地工作了......无论如何,NSImage 是在我想要绘制的 ImageView 中显示正在处理的图像目标线(黄色)和 ROI(灰色)。扫描图像并且必须为检测到的线重新调整/重新缩放/翻译以适合目标线。这样做是为了改善最佳标记识别的结果。 【参考方案1】:在 JPEG 图像上画一条简单的线
// load JPEG from main bundle
guard let path = Bundle.main.pathForImageResource(NSImage.Name("picture.jpg")),
let image = NSImage(contentsOfFile: path)
else fatalError()
let size = image.size
image.lockFocus() // prepare image for drawing
NSColor.red.setStroke()
NSBezierPath.strokeLine(from: .zero, to: NSPoint(x: size.width, y: size.height))
image.unlockFocus() // drawing commands done
上面的代码从左下角到右上角画了一条红线。
如果你手头有NSImageView
,你可以直接使用图片:
@IBOutlet weak var imageView: NSImageView!
...
imageView.image = image
【讨论】:
谢谢你,djromero。这很有帮助,而且解决方案的优雅让我很沮丧。但是,正如预期的那样,原点 (0,0) 位于图像的左下角,并且大小不是以像素为单位的 - 正如我在原始帖子中提到的那样。有什么想法吗? 这样做,我得到了一个与 CGImage 大小相同的 NSImage,我能够画线并显示 NSImage,并且还可以在像素级进行霍夫变换......但是NSImage 的原点还在左下角! let imageAsData = try Data(contentsOf: selectedFiles[0]) let imageProvider = CGDataProvider(data: imageAsData as CFData) var myImage = CGImage(jpegDataProviderSource: imageProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent) let imageAsNSImage= NSImage(cgImage: myImage!, size: NSZeroSize)【参考方案2】:感谢 djromero,这是我刚刚达成的解决方案:
// Load the JPEG image from disk into a CGImage
//
let imageAsData = try Data(contentsOf: chosenFiles[0])
let imageProvider = CGDataProvider(data: imageAsData as CFData)
var myImage = CGImage(jpegDataProviderSource: imageProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
// Create a NSImage from the CGImage (with the same width and height in pixels)
//
let imageAsNSImage=NSImage(cgImage: myImage!, size: NSZeroSize)
// Drawing a simple line
//
imageAsNSImage.lockFocusFlipped(true) // Otherwise, the origin is at the lower left corner
NSColor.red.setStroke()
NSBezierPath.strokeLine(from: targetStart, to: targetEnd)
imageAsNSImage.unlockFocus()
// Show the NSImage in the NSImageView
//
myImageView.image = imageAsNSImage
【讨论】:
以上是关于在 JPEG 图像上画一条简单的线的主要内容,如果未能解决你的问题,请参考以下文章