Scala, position objects on a circumference - oop

I am trying to populate a circumference with points located at equal intervals. Here is the code (it uses some Processing, but it is not crucial for understanding):
class Circle (x: Float, y: Float, subdivisions: Int, radius: Float) extends WorldObject(x, y) {
def subs = subdivisions
def r = radius
val d = r + r
def makePoints() : List[Glyph] = {
val step = PConstants.TWO_PI / subdivisions
val points = List.make(subdivisions, new Glyph())
for(i <- 0 to subdivisions - 1) {
points(i) position (PApplet.cos(step * i) * r + xPos, PApplet.sin(step * i) * r + yPos)
}
points
}
val points: List[Glyph] = makePoints()
override def draw() {
applet fill 0
applet stroke 255
applet ellipse(x, y, d, d)
applet fill 255
points map(_.update())
}
}
class Glyph(x: Float, y: Float) extends WorldObject(x, y){
def this() = this(0, 0)
override def draw() {
applet ellipse(xPos, yPos, 10, 10)
}
}
object WorldObject {
}
abstract class WorldObject(var xPos: Float, var yPos: Float) {
def this() = this(0, 0)
def x = xPos
def y = yPos
def update() {
draw()
}
def draw()
def position(x: Float, y: Float) {
xPos = x
yPos = y
}
def move(dx: Float, dy: Float) {
xPos += dx
yPos += dy
}
}
The strange result that I get is that all the points are located at a single place. I have experimented with println checks... the checks in the makePoints() method shows everything ok, but checks in the Circle.draw() or even right after the makePoints() show the result as I see it on the screen - all points are located in a single place, right where the last of them is generated, namely x=430.9017 y=204.89435 for a circle positioned at x=400 y=300 and subdivided to 5 points. So somehow they all get collected into the place where the last of them sits.
Why is there such a behavior? What am I doing wrong?
UPD: We have been able to locate the reason, see below:
Answering the question, user unknown changed the code to use the fill method instead of make. The main relevant difference between them is that make pre-computes it's arguments and fill does not. Thus make fills the list with totally identical items. However, fill repeats the computation on each addition. Here are the source codes of these methods from Scala sources:
/** Create a list containing several copies of an element.
*
* #param n the length of the resulting list
* #param elem the element composing the resulting list
* #return a list composed of n elements all equal to elem
*/
#deprecated("use `fill' instead", "2.8.0")
def make[A](n: Int, elem: A): List[A] = {
val b = new ListBuffer[A]
var i = 0
while (i < n) {
b += elem
i += 1
}
b.toList
}
And the fill method:
/** Produces a $coll containing the results of some element computation a number of times.
* #param n the number of elements contained in the $coll.
* #param elem the element computation
* #return A $coll that contains the results of `n` evaluations of `elem`.
*/
def fill[A](n: Int)(elem: => A): CC[A] = {
val b = newBuilder[A]
b.sizeHint(n)
var i = 0
while (i < n) {
b += elem
i += 1
}
b.result
}

I changed a lot of variables forth and back (def x = ... => def x () = , x/ this.x and x/xPos and so on) added println statements and removed (P)applet-stuff, which made the compiler complain.
Providing a compilable, runnable, standalone demo would be beneficial. Here it is:
class Circle (x: Float, y: Float, subdivisions: Int, radius: Float)
extends WorldObject (x, y) {
def subs = subdivisions
def r = radius
val d = r + r
def makePoints() : List[Glyph] = {
// val step = PConstants.TWO_PI / subdivisions
val step = 6.283F / subdivisions
val points = List.fill (subdivisions) (new Glyph ())
for (i <- 0 to subdivisions - 1) {
// points (i) position (PApplet.cos (step * i) * r + xPos,
// PApplet.sin (step * i) * r + yPos)
val xx = (math.cos (step * i) * r).toFloat + xPos
val yy = (math.sin (step * i) * r).toFloat + yPos
println (xx + ": " + yy)
points (i) position (xx, yy)
}
points
}
val points: List [Glyph] = makePoints ()
override def draw () {
/*
applet fill 0
applet stroke 255
applet ellipse(x, y, d, d)
applet fill 255
*/
// println ("Circle:draw () upd-> " + super.x () + "\t" + y () + "\t" + d);
points map (_.update ())
println ("Circle:draw () <-upd " + x + "\t" + y + "\t" + d);
}
}
class Glyph (x: Float, y: Float) extends WorldObject (x, y) {
def this () = this (0, 0)
override def draw() {
// applet ellipse (xPos, yPos, 10, 10)
println ("Glyph:draw (): " + xPos + "\t" + yPos + "\t" + 10);
}
}
object Circle {
def main (as: Array [String]) : Unit = {
val c = new Circle (400, 300, 5, 100)
c.draw ()
}
}
object WorldObject {
}
abstract class WorldObject (var xPos: Float, var yPos: Float) {
def this () = this (0, 0)
def x = xPos
def y = yPos
def update () {
draw ()
}
def draw ()
def position (x: Float, y: Float) {
xPos = x
yPos = y
// println (x + " ?= " + xPos + " ?= " + (this.x ()))
}
def move (dx: Float, dy: Float) {
xPos += dx
yPos += dy
}
}
My result is:
500.0: 300.0
430.9052: 395.1045
319.10266: 358.78452
319.09177: 241.23045
430.8876: 204.88977
Glyph:draw (): 500.0 300.0 10
Glyph:draw (): 430.9052 395.1045 10
Glyph:draw (): 319.10266 358.78452 10
Glyph:draw (): 319.09177 241.23045 10
Glyph:draw (): 430.8876 204.88977 10
Circle:draw () <-upd 400.0 300.0 200.0
Can you spot the difference?
You should create a copy of your code, and stepwise remove code, which isn't necessary to reproduce the error, checking, whether the error is still present. Then you should reach a much smaller problem, or find the error yourself.

Related

How can I measure the height and width of a text in Jetpack Compose Canvas?

I'm use Jetpack Compose Canvas to draw a division circle. The min value of the division circle is 20, and the max value of the division circle is 120.
So I write the Code A, and I get the result Image A as expected except the label.
From the Image A, I find the label 0, 20, 40 are on good position, and the label 60, 80, 100, 120 are not on good position.
1: It seems that I need to measure the height and width of a text,then adjust the position of the text, if so, how can I measure the height and width of a text?
2: Is there other way to place these text on apposite position without measurement the height and width of text?
Code A
#Composable
fun setCanvas(maxCountList: MaxCountList<Double>) {
Canvas(
modifier = Modifier
) {
val axisPaint = Paint()
val textPaint = TextPaint()
drawIntoCanvas {
val orig = MyPoint(size.width / 2, size.height / 2)
val temp = min(size.height, size.width)
val radius = temp / 2 - 10
it.drawCircle(Offset(x = 0f.toX(orig), y = 0f.toY(orig)), radius, axisPaint)
val lineOffset = 5.0f
val lineLength = 20.0f
val labelOffset = 10.0f
val point1 = radius - lineOffset
val point2 = radius - lineOffset - lineLength
val point3 = radius - lineOffset - lineLength - labelOffset
(0..6).forEach { i ->
val radians = Math.toRadians(225 - i * 45.0)
val x1 = point1 * cos(radians).toFloat()
val x2 = point2 * cos(radians).toFloat()
val x3 = point3 * cos(radians).toFloat()
val y1 = point1 * sin(radians).toFloat()
val y2 = point2 * sin(radians).toFloat()
val y3 = point3 * sin(radians).toFloat()
it.drawLine(
Offset(x = x1.toX(orig), y = y1.toY(orig)),
Offset(x = x2.toX(orig), y = y2.toY(orig)),
axisPaint
)
val label=(i * 20).toString()
it.nativeCanvas.drawText(label, x3.toX(orig), y3.toY(orig), textPaint)
}
}
}
}
//Convert X to new coordinate
fun Float.toX(originCoordinate: MyPoint) :Float {
return originCoordinate.x+this
}
//Convert Y to new coordinate
fun Float.toY(originCoordinate: MyPoint):Float {
return originCoordinate.y-this
}
class MyPoint (val x:Float, val y: Float)
Image A
you can use TextMeasurer.measure in jetpack compose 1.3.0-alpha2 onwards
you can check samples here
https://android-review.googlesource.com/c/platform/frameworks/support/+/2135315/4/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/DrawTextDemo.kt

How to round and resize two rectangles and four circles creating a square shape in Kotlin?

I am learning Kotlin and I am facing a challenge here:
How can I round and resize two rectangles and four circles creating a square shape in Kotlin using canvas, until it gets a ball or a perfect square?
We have this code already:
import pt.isel.canvas.*
private fun Canvas.drawSquare(r: RoundSquare) {
erase()
val f = (r.side/2 * r.round/100f).toInt()
val pos = Position(r.center.x,r.center.y)
val square =
drawRect(pos.x-150, pos.y-100,r.side+100,r.side, r.color)
drawRect(pos.x-100, pos.y-150, r.side, r.side+100, r.color)
drawCircle(pos.x-100, pos.y-100, f, r.color)
drawCircle(pos.x+100, pos.y-100, f, r.color)
drawCircle(pos.x-100, pos.y+100, f, r.color)
drawCircle(pos.x+100, pos.y+100, f, r.color)
return square
}
fun main () {
onStart {
val cv = Canvas(600, 400, WHITE)
var roundSquare = RoundSquare(Position(300, 200), 200, 50, GREEN)
cv.drawSquare(roundSquare)
cv.drawText(10,400,"center=(${roundSquare.center.x},${roundSquare.center.y}) side=${roundSquare.side} round=${roundSquare.round}% color=0x${roundSquare.color.toString(16).padStart(6, '0').toUpperCase()}",BLACK,15)
cv.onMouseDown {
roundSquare = roundSquare.copy(center = Position(it.x, it.y))
cv.drawSquare(roundSquare)
return#onMouseDown cv.drawText(10,390,"center=(${roundSquare.center.x},${roundSquare.center.y}) side=${roundSquare.side} round=${roundSquare.round}% color=0x${roundSquare.color.toString(16).padStart(6, '0').toUpperCase()}",BLACK,15)
}
cv.onKeyPressed {
roundSquare = roundSquare.processKey(it.char)
cv.drawSquare(roundSquare)
return#onKeyPressed cv.drawText(10,400,"center=(${roundSquare.center.x},${roundSquare.center.y}) side=${roundSquare.side} round=${roundSquare.round}% color=0x${roundSquare.color.toString(16).padStart(6, '0').toUpperCase()}",BLACK,15)
}
onFinish { println("Bye") }
}
}
import pt.isel.canvas.BLACK
import pt.isel.canvas.WHITE
data class Position (val x:Int, val y:Int)
data class RoundSquare (val center:Position, val side:Int, val round:Int, val color:Int)
val RANGE_SIZE = 10..400
val ROUND = 0..100
val RANDOM_COLOR = BLACK..WHITE
fun RoundSquare.processKey(key: Char) = when {
key=='r' && round > ROUND.first -> copy(round = round - 1, side = side -1)
key=='R' && round < ROUND.last -> copy(round = round + 1, side = side + 1)
key=='s' && side > RANGE_SIZE.first -> copy(side = side - 1, round = round - 1)
key=='S' && side < RANGE_SIZE.last -> copy(side = side + 1, round = round + 1)
key == 'c' -> copy(color = RANDOM_COLOR.random())
else -> this
}
But it doesn't give me the output I need. This is the output:
Which can be resized till it shows a perfect ball or perfect square, by resizing sides and rounding circles.
If anyone could help me, I would really appreciate it.
Thanks in advance,
Let rounded shape center is (cx, cy), halfsize is hs.
Left x-coordinate is lx = cx - hs
Top y-coordinate is ty = cy - hs
Right x-coordinate is rx = cx + hs
Bottom y-coordinate is by = cy + hs
We want to change parameter t from 0 to 1 (or from 0 to 100%) to make needed roundness.
Circles radius is (round to integer if needed)
R = hs * t
Circle centers coordinates:
lx + R, ty + R
rx - R, ty + R
rx - R, by - R
lx + R, by - R
Two corners of rectangles:
(lx + R, ty) - (rx - R, by)
(lx, ty + R) - (rx, by - R)

Kotlin Calculating with BigDecimal vs Double

I have 2 Functions. One uses BigInteger and BigDecimal. I want to calculate sin(z) using the Taylor series:
Here is my code:
fun sinus(z: BigDecimal, upperBound: Int = 100): BigDecimal = calcSin(z, upperBound)
fun cosinus(z: BigDecimal, upperBound: Int = 100): BigDecimal = calcSin(z, upperBound, false)
fun calcSin(z: BigDecimal, upperBound: Int = 100, isSin: Boolean = true): BigDecimal {
var erg: BigDecimal = BigDecimal.ZERO
for (n in 0..upperBound) {
// val zaehler = (-1.0).pow(n).toBigDecimal() * z.pow(2 * n + (if (isSin) 1 else 0))
// val nenner = fac(2 * n + (if (isSin) 1 else 0)).toBigDecimal()
val zaehler = (-1.0).pow(n).toBigDecimal() * z.pow(2 * n + 1)
val nenner = fac(2 * n + 1).toBigDecimal()
erg += (zaehler / nenner)
}
return erg
}
fun calcSin(z: Double, upperBound: Int = 100): Double {
var res = 0.0
for (n in 0..upperBound) {
val zaehler = (-1.0).pow(n) * z.pow(2 * n + 1)
val nenner = fac(2 * n + 1, true)
res += (zaehler / nenner)
}
return res
}
fun fac(n: Int): BigInteger = if (n == 0 || n == 1) BigInteger.ONE else n.toBigInteger() * fac(n - 1)
fun fac(n: Int, dummy: Boolean): Double = if (n == 0 || n == 1) 1.0 else n.toDouble() * fac(n - 1, dummy)
According to Google, Sin(1) is
0.8414709848
The Output of the following is however:
println("Sinus 1: ${sinus(1.0.toBigDecimal())}")
println("Sinus 1: ${sinus(1.0.toBigDecimal()).toDouble()}")
println("Sinus 1: ${sinus(1.0.toBigDecimal(), 1000)}")
println("Sinus 1: ${calcSin(1.0)}")
Output:
Sinus 1: 0.8414373208078281027995610599000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Sinus 1: 0.8414373208078281
Sinus 1: 0.8414373208078281027995610599000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Sinus 1: 0.8414709848078965
Wha am I missing? Why does the Double-Variant gives the correct value, while The BigDecimal doesn't? Even with 1000 Iterations.
The commented out code was meant for calculation Cos as well, but wanted to figure out that Problem first, so i made both Functions look the same
In the BigDecimal variant, try replacing erg += (zaehler / nenner) with erg += (zaehler.divide(nenner, 20, RoundingMode.HALF_EVEN))
I suspect that the defaults for scaling the division results (as described here https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html) are not what you want.
BTW - I assume that performance is not part of the exercise, otherwise your implementation of factorial is a low hanging fruit.

Assignment problem - What am I doing wrong?

I am working on image seam carving project, looking for some help. Can someone tell me what am I doing wrong here, Hyperskill is not accepting my solution. I am pretty sure I did not understand the project statement correctly. (I’ve been fighting it for a week)
Project: https://hyperskill.org/projects/100/stages/553/implement
First I am finding the minimum seam from all possible seams.
var minX = 0
// (minSeamX, 0) would be the coordinate of the minimum seam
var minSeamX = 0
var minSeam = Double.MAX_VALUE
//Starting from top left find the sum of pixel energies for all possible seams(#width number of possible seams)
for (column in 0 until width) {
var totalSeam = 0.0
var xHigh = column
var xLow = column
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
if (x < 0 || x > width - 1) continue
val energy = calculateEnergy(x, y, bufferedImage)
// println("Energy $x $y $energy")
if (energy < min) {
min = energy
minX = x
}
}
totalSeam += min
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
if (totalSeam < minSeam) {
minSeamX = column
minSeam = totalSeam
}
println("total:$totalSeam")
}
after that I am applying the color to the minimum seam pixels
var xLow = minSeamX
var xHigh = minSeamX
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
val energy = calculateEnergy(x, y, bufferedImage)
if (energy < min) {
min = energy
minX = x
}
}
val createGraphics = applyColor(outImage, minX, y)
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
Complete code
package seamcarving
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import kotlin.math.pow
import kotlin.math.sqrt
fun main(args: Array<String>) {
val bufferedImage = ImageIO.read(File("/Users/name/Downloads/images/blue.png"))
val outImage = ImageIO.read(File("/Users/name/Downloads/images/blue.png"))
val height = bufferedImage.height
val width = bufferedImage.width
var minX = 0
// (minSeamX, 0) would be the coordinate of the minimum seam
var minSeamX = 0
var minSeam = Double.MAX_VALUE
//Starting from top left find the sum of pixel energies for all possible seams(#width number of possible seams)
for (column in 0 until width) {
var totalSeam = 0.0
var xHigh = column
var xLow = column
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
if (x < 0 || x > width - 1) continue
val energy = calculateEnergy(x, y, bufferedImage)
// println("Energy $x $y $energy")
if (energy < min) {
min = energy
minX = x
}
}
totalSeam += min
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
if (totalSeam < minSeam) {
minSeamX = column
minSeam = totalSeam
}
println("total:$totalSeam")
}
var xLow = minSeamX
var xHigh = minSeamX
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
val energy = calculateEnergy(x, y, bufferedImage)
if (energy < min) {
min = energy
minX = x
}
}
val createGraphics = applyColor(outImage, minX, y)
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
// for (x in 0 until width) {
// for (y in 0 until height) {
// val intensity = ((255.0 * array[x][y]) / max).toInt()
// val color = Color(intensity, intensity, intensity)
//// outputImage.setRGB(x, y, intensity)
// createGraphics.paint = color
// createGraphics.fillRect(x, y, 1, 1)
// }
// }
ImageIO.write(outImage, "png", File("out.png"))
// ImageIO.write(bufferedImage, "png", File("${args[3]}"))
}
private fun applyColor(outputImage: BufferedImage, maxX: Int, maxY: Int): Graphics2D? {
val createGraphics = outputImage.createGraphics()
val color = Color(255, 0, 0)
createGraphics.paint = color
createGraphics.fillRect(maxX, maxY, 1, 1)
return createGraphics
}
private fun calculateEnergy(x: Int, y: Int, bufferedImage: BufferedImage): Double {
return sqrt(getXGradient(x, y, bufferedImage) + getYGradient(x, y, bufferedImage))
}
fun getXGradient(x: Int, y: Int, inImage: BufferedImage): Double {
val width = inImage.width
var xx = x
var yy = y
if (x == 0) xx = 1
if (x == width - 1) xx = x - 1
val lc = Color(inImage.getRGB(xx - 1, yy))
val rc = Color(inImage.getRGB(xx + 1, yy))
return (lc.red - rc.red).toDouble().pow(2.0) + (lc.green - rc.green).toDouble().pow(2.0) + (lc.blue - rc.blue).toDouble().pow(2.0)
}
fun getYGradient(x: Int, y: Int, inImage: BufferedImage): Double {
val height = inImage.height
var xx = x
var yy = y
if (y == 0) yy = 1
if (y == height - 1) yy = y - 1
val lc = Color(inImage.getRGB(xx, yy - 1))
val rc = Color(inImage.getRGB(xx, yy + 1))
return (lc.red - rc.red).toDouble().pow(2.0) + (lc.green - rc.green).toDouble().pow(2.0) + (lc.blue - rc.blue).toDouble().pow(2.0)
}

Binary operator '+=' cannot be applied to operands of type 'Int' and 'UInt8'

Translating Obj-C to Swift. As you can see I declared let buf = UnsafeMutablePointer<UInt8>(CVPixelBufferGetBaseAddress(cvimgRef)) so I'm getting the error in the for loop below it.
Binary operator '+=' cannot be applied to operands of type 'Int' and 'UInt8'
Also as a little addendum I don't know how to translate the remaining Obj-C code below the for loop. What does that slash mean and how do I deal with the pointer? I have to say UnsafeMutableFloat somewhere?
// process the frame of video
func captureOutput(captureOutput:AVCaptureOutput, didOutputSampleBuffer sampleBuffer:CMSampleBuffer, fromConnection connection:AVCaptureConnection) {
// if we're paused don't do anything
if currentState == CurrentState.statePaused {
// reset our frame counter
self.validFrameCounter = 0
return
}
// this is the image buffer
var cvimgRef:CVImageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer)
// Lock the image buffer
CVPixelBufferLockBaseAddress(cvimgRef, 0)
// access the data
var width: size_t = CVPixelBufferGetWidth(cvimgRef)
var height:size_t = CVPixelBufferGetHeight(cvimgRef)
// get the raw image bytes
let buf = UnsafeMutablePointer<UInt8>(CVPixelBufferGetBaseAddress(cvimgRef))
var bprow: size_t = CVPixelBufferGetBytesPerRow(cvimgRef)
var r = 0
var g = 0
var b = 0
for var y = 0; y < height; y++ {
for var x = 0; x < width * 4; x += 4 {
b += buf[x]; g += buf[x + 1]; r += buf[x + 2] // error
}
buf += bprow() // error
}
Remaining Obj-C code.
r/=255*(float) (width*height);
g/=255*(float) (width*height);
b/=255*(float) (width*height);
You have a lot of type mismatch error.
The type of x should not be UInt8 because x to increase until the value of the width.
for var x:UInt8 = 0; x < width * 4; x += 4 { // error: '<' cannot be applied to operands of type 'UInt8' and 'Int'
So fix it like below:
for var x = 0; x < width * 4; x += 4 {
To increment the pointer address, you can use advancedBy() function.
buf += bprow(UnsafeMutablePointer(UInt8)) // error: '+=' cannot be applied to operands of type 'UnsafeMutablePointer<UInt8>' and 'size_t'
Like below:
var pixel = buf.advancedBy(y * bprow)
And this line,
RGBtoHSV(r, g, b) // error
There are no implicit casts in Swift between CGFloat and Float unfortunately. So you should cast explicitly to CGFloat.
RGBtoHSV(CGFloat(r), g: CGFloat(g), b: CGFloat(b))
The whole edited code is here:
func RGBtoHSV(r: CGFloat, g: CGFloat, b: CGFloat) -> (h: CGFloat, s: CGFloat, v: CGFloat) {
var h: CGFloat = 0.0
var s: CGFloat = 0.0
var v: CGFloat = 0.0
let col = UIColor(red: r, green: g, blue: b, alpha: 1.0)
col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
return (h, s, v)
}
// process the frame of video
func captureOutput(captureOutput:AVCaptureOutput, didOutputSampleBuffer sampleBuffer:CMSampleBuffer, fromConnection connection:AVCaptureConnection) {
// if we're paused don't do anything
if currentState == CurrentState.statePaused {
// reset our frame counter
self.validFrameCounter = 0
return
}
// this is the image buffer
var cvimgRef = CMSampleBufferGetImageBuffer(sampleBuffer)
// Lock the image buffer
CVPixelBufferLockBaseAddress(cvimgRef, 0)
// access the data
var width = CVPixelBufferGetWidth(cvimgRef)
var height = CVPixelBufferGetHeight(cvimgRef)
// get the raw image bytes
let buf = UnsafeMutablePointer<UInt8>(CVPixelBufferGetBaseAddress(cvimgRef))
var bprow = CVPixelBufferGetBytesPerRow(cvimgRef)
var r: Float = 0.0
var g: Float = 0.0
var b: Float = 0.0
for var y = 0; y < height; y++ {
var pixel = buf.advancedBy(y * bprow)
for var x = 0; x < width * 4; x += 4 { // error: '<' cannot be applied to operands of type 'UInt8' and 'Int'
b += Float(pixel[x])
g += Float(pixel[x + 1])
r += Float(pixel[x + 2])
}
}
r /= 255 * Float(width * height)
g /= 255 * Float(width * height)
b /= 255 * Float(width * height)
//}
// convert from rgb to hsv colourspace
var h: Float = 0.0
var s: Float = 0.0
var v: Float = 0.0
RGBtoHSV(CGFloat(r), g: CGFloat(g), b: CGFloat(b)) // error
}