我正在使用scala(2.12.6),OpenCV和Eclipse(Neon 3a)在图像上进行人脸检测。
我有一组检测到的面孔,我想通过使用一个小的gui应用程序来验证,在这个应用程序中可以进行图像的缩放和平移。对于实现,我选择将检测到的面集传递给主gui对象,该对象在trun中具有用于提取用户验证结果的公共方法(一旦验证完成):一组经过验证的自动检测和一组移除的检测和一组手动添加的检测。
最初检测到的面部显示为绿色矩形:
为了知道何时可以从gui对象中提取信息,需要暂停执行主程序,直到用户确认(通过按下按钮)完成验证。为了实现这种阻止,我让自己受到Return a value from a Scala + Swing app的启发,其中Luigi Plinge建议使用Reactor
来收听确认按钮。
此设置正常工作,直到我开始单击图像以操作检测到的面部集或者我调整gui窗口的大小。在这些情况下,gui会选择确认按钮事件,但似乎Reactor
对gui确认按钮感到聋。
下面我使用相同的实现策略添加了类似gui的代码(简化:仅提取最后一次用户点击的坐标),这与调整gui窗口大小或单击图像内部存在相同的问题。
此外,在启动应用程序后,我注意到一些非常奇怪的行为:
代码示例的图片:qm.png
import scala.concurrent.{ Promise, Await }
import scala.concurrent.duration.Duration
import scala.util.{ Try, Success, Failure }
import scala.swing.{ MainFrame, Label, ScrollPane, BoxPanel, Orientation, Button, Action, Swing, Reactor }
import scala.swing.event.{ ButtonClicked, WindowClosing, MouseClicked }
import java.io.File
import java.awt.image.BufferedImage
import java.awt.{ Point, BasicStroke, Color }
import javax.swing.ImageIcon
import javax.imageio.ImageIO
object BecomingDeaf02 {
class gui( fh:File, x0:Int, y0:Int ) extends MainFrame {
// public buttons: the calling function listens to these to determine whether the user is ready to continue
val okButton = new Button { action = Action("OK") { println( "[gui] OK button pushed..." ) } }
val abortButton = new Button { action = Action("Abort Validation") { println( "[gui] Abort button pushed..." ) } }
// in reality these are lists of rectangles (detected objects), which can be modified by user-gui-interaction
private var x = x0
private var y = y0
def getX():Int = x
def getY():Int = y
private var sf = 1.0f // scale factor
private val imgIconLabel = new Label {
def update():Unit = {
val imgBase = ImageIO.read(fh)
val g = imgBase.createGraphics()
g.setStroke(new BasicStroke(3))
g.setColor(Color.RED)
g.drawOval(x, y, 3, 3)
val imgIcon = new ImageIcon(imgBase)
val w = math.round(imgIcon.getIconWidth*sf)
val h = math.round(imgIcon.getIconHeight*sf)
icon_=(new ImageIcon( imgIcon.getImage.getScaledInstance(w, h, java.awt.Image.SCALE_SMOOTH) ))
}
update()
}
private val scrPane = new ScrollPane {
def updateXY( p:Point ):Unit ={
val xOffset = (this.size.getWidth.toInt - imgIconLabel.icon.getIconWidth)/2
val yOffset = (this.size.getHeight.toInt - imgIconLabel.icon.getIconHeight)/2
// to simplify the example code, scroll bars are not taken into account
x = math.round( (p.x - xOffset)/sf )
y = math.round( (p.y - yOffset)/sf )
}
contents_=(imgIconLabel)
listenTo(mouse.clicks)
reactions += { case MouseClicked(_,p,_,_,_) => { println(s"[gui.scrPane] clicked @ (${p.x},${p.y})"); updateXY(p); imgIconLabel.update() } }
}
private val boxP_flowControl = new BoxPanel( Orientation.Horizontal ) {
contents += okButton
contents += Swing.HStrut(10)
contents += abortButton
contents += Swing.HStrut(10)
contents += Button("zoom +") { sf = sf*1.2f; imgIconLabel.update() }
contents += Button("zoom -") { sf = sf*0.8f; imgIconLabel.update() }
}
// main gui component
title = "Validation Window"
contents = new BoxPanel( Orientation.Vertical ) {
contents += scrPane
contents += Swing.HStrut(10)
contents += boxP_flowControl
}
} // class gui
def main(args: Array[String]) {
val imgFP = """./resources/qm.png"""
val ui = new gui( new File(imgFP), -1, -1 )
ui.visible = true
val promisedUserResponse = Promise[String]()
var val1 = 0
var val2 = 0
new Reactor {
listenTo(ui.okButton)
listenTo(ui.abortButton)
listenTo(ui)
reactions += {
case ButtonClicked(b) if b == ui.okButton => {
println( s"[main] Reaction detected: user clicked OK button. Processing corresponding reaction block..." )
val1 = ui.getX()
val2 = ui.getY()
promisedUserResponse.success("Status: validated user selection extracted.")
}
case ButtonClicked(b) if b == ui.abortButton => promisedUserResponse.failure(new Exception( "User clicked Abort button...") )
case e: WindowClosing => promisedUserResponse.failure(new Exception( "User closed window before chosing...") )
}
}
// this blocks until the future (linked to promisedUserResponse) is complete
val userResponse = Try( Await.result(promisedUserResponse.future, Duration.Inf) )
ui.visible = false
userResponse match {
case Success(str) => println( s"[main] user clicked @ ($val1,$val2) $str" )
case Failure(exc) => println( s"[main] Failed to complete validation: '${exc.getMessage}'" )
}
}
}
我在这里做错了什么?所有帮助都非常受欢迎!