How to add Tuples and apply a ceiling/clamp function in F# - f#

So I am working on a project using F# for some SVG line manipulations.
I thought it would be good to represent color an RGB value as a tuple (R,G,B). It just made sense to me. Well since my project involves generating SVG lines in a loop. I decided to have a color offset, conveniently also represented in a tuple (Roffset, Goffset, Boffset)
An offset in this case represents how much each line differs from the previous.
I got to a point where I needed to add the tuples. I thought since they were of the same dimensions and types, it would be fine. But apparently not. I also checked the MSDN on tuples, but I did not find anything about how to add them or combine them.
Here is what I tried. Bear in mind I tried to omit as much irrelevant code as possible since this is a long class definition with LOTS of members.
type lineSet ( 10+ params omitted ,count, colorOff :byte*byte*byte, color :byte*byte*byte ,strokeWid , strokeWidthOff ) =
member val Color = color with get, set
member val ColorOffset = colorOff with get, set
member val lineCount = count with get, set
interface DrawingInterfaces.IRepresentable_SVG with
member __.getSVGRepresenation() =
let mutable currentColor = __.Color
for i in 1..__.lineCount do
currentColor <- currentColor + __.ColorOffset
That last line of code is what I wanted to do. However, it appears you cannot add tuples directly.
I also need a way to clamp the result so it cannot go over 255, but I suspect a simple try with block will do the trick. OR I could let the params take a type int*int*int and just use an if to reset it back to 255 each time.

As I mentioned in the comments, the clamping function in your code does not actually work - you need to convert the numbers to integers before doing the addition (and then you can check if the integer is greater than 255). You can do something like this:
let addClamp (a:byte) (b:byte) =
let r = int a + int b
if r > 255 then 255uy else byte r
Also, if you work with colors, then it might make sense to define a custom color type rather than passing colors around as tuples. That way, you can also define + on colors (with clamping) and it will make your code simpler (but still, 10 constructor arguments is a bit scary, so I'd try to think if there is a way to simplify that a bit). A color type might look like this:
type Color(r:byte, g:byte, b:byte) =
static let addClamp (a:byte) (b:byte) =
let r = int a + int b
if r > 255 then 255uy else byte r
member x.R = r
member x.B = b
member x.G = g
static member (+) (c1:Color, c2:Color) =
Color(addClamp c1.R c2.R, addClamp c1.G c2.G,addClamp c1.B c2.B)
Using the type, you can then add colors pretty easily and do not have to add clamping each time you need to do that. For example:
Color(255uy, 0uy, 0uy) + Color(1uy, 0uy, 0uy)
But I still think you could make the code more readable and more composable by refactoring some of the visual properties (like stroke & color) to a separate type and then just pass that to LineSet. This way you won't have 10+ parameters to a constructor and your code will probably be more flexible too.

Here is a modified version of your code which I think is a bit nicer
let add3DbyteTuples (tuple1:byte*byte*byte , tuple2:byte*byte*byte) =
let inline intify (a,b,c) = int a,int b,int c
let inline tripleadd (a,b,c) (d,e,f) = a+d,b+e,c+f
let clamp a = if a > 255 then 255 else a
let R,G,B = tripleadd (intify tuple1) (intify tuple2)
clamp R,clamp G,clamp B

Related

Computing remainder without using modulus operator F#

I have implemented my code which is basically to compute remainder in two numbers without using modulus operator however, I am stuck in a situation which is just hectic. I know the logic however I am newbie in f# and dont know how to implement it.
let rec modulus a b =
if b = 0 Console.WriteLine("Sorry Wrong Divisor")
let bool neg = a < 0
a = abs a
b = abs b
modulus(val-divisor,divisor)
All I know is I am getting a pretty basic mistake here, Any help,
The first step towards getting this to work is to fix your indentation and turn your sketch into valid F# code that actually compiles and runs - that should help you get to the next step, which is to fix the logic of the implementation.
A minimal code that is similar to yours and actually runs looks like this:
let rec modulus value divisor : int =
printfn "value=%d, divisor=%d" value divisor
if divisor = 0 then Console.WriteLine("Sorry Wrong Divisor")
let neg = value < 0
let value = abs value
let divisor = abs divisor
modulus (value-divisor) divisor
modulus 10 5
I fixed the indentation - F# is indentation sensitive, so this matters.
I replaced your a = abs a with let - the let keyword defines a new variable, hiding the existing one (as you cannot mutate existing variables - they are immutable in F#)
I renamed your variables to consistently use divisor and value names
I added printfn so that you can see how the function runs (it will get into an infinite loop, because it currently never checks for the termination condition!)
I had to add type annotation : int to say that the result will be int - as your function never returns, this is required (but you can remove it once you fix this)
You can calculate modulus in simpler way
let modulus a b=
if b = 0.0 then failwith "Cannot divide by zero"
a - b * truncate(a / b);

iOS slow image pixel iterating

I am trying to implement RGB histogram computation for images in Swift (I am new to iOS).
However the computation time for 1500x1000 image is about 66 sec, which I consider to be too slow.
Are there any ways to speed up image traversal?
P.S. current code is the following:
func calcHistogram(image: UIImage) {
let bins: Int = 20;
let width = Int(image.size.width);
let height = Int(image.size.height);
let binStep: Double = Double(bins-1)/255.0
var hist = Array(count:bins, repeatedValue:Array(count:bins, repeatedValue:Array(count:bins, repeatedValue:Int())))
for i in 0..<bins {
for j in 0..<bins {
for k in 0..<bins {
hist[i][j][k] = 0;
}
}
}
var pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage))
var data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
for x in 0..<width {
for y in 0..<height {
var pixelInfo: Int = ((width * y) + x) * 4
var r = Double(data[pixelInfo])
var g = Double(data[pixelInfo+1])
var b = Double(data[pixelInfo+2])
let r_bin: Int = Int(floor(r*binStep));
let g_bin: Int = Int(floor(g*binStep));
let b_bin: Int = Int(floor(b*binStep));
hist[r_bin][g_bin][b_bin] += 1;
}
}
}
As noted in my comment on the question, there are some things you might rethink before you even try to optimize this code.
But even if you do move to a better overall solution like GPU-based histogramming, a library, or both... There are some Swift pitfalls you're falling into here that are good to talk about so you don't run into them elsewhere.
First, this code:
var hist = Array(count:bins, repeatedValue:Array(count:bins, repeatedValue:Array(count:bins, repeatedValue:Int())))
for i in 0..<bins {
for j in 0..<bins {
for k in 0..<bins {
hist[i][j][k] = 0;
}
}
}
... is initializing every member of your 3D array twice, with the same result. Int() produces a value of zero, so you could leave out the triple for loop. (And possibly change Int() to 0 in your innermost repeatedValue: parameter to make it more readable.)
Second, arrays in Swift are copy-on-write, but this optimization can break down in multidimensional arrays: changing an element of a nested array can cause the entire nested array to be rewritten instead of just the one element. Multiply that by the depth of nested arrays and number of element writes you have going on in a double for loop and... it's not pretty.
Unless there's a reason your bins need to be organized this way, I'd recommend finding a different data structure for them. Three separate arrays? One Int array where index i is red, i + 1 is green, and i + 2 is blue? One array of a custom struct you define that has separate r, g, and b members? See what conceptually fits with your tastes or the rest of your app, and profile to make sure it works well.
Finally, some Swift style points:
pixelInfo, r, g, and b in your second loop don't change. Use let, not var, and the optimizer will thank you.
Declaring and initializing something like let foo: Int = Int(whatever) is redundant. Some people like having all their variables/constants explicitly typed, but it does make your code a tad less readable and harder to refactor.
Int(floor(x)) is redundant — conversion to integer always takes the floor.
If you have some issues about performance in your code, first of all, use Time Profiler from Instruments. You can start it via Xcode menu Build->Profile, then, Instruments app opened, where you can choose Time Profiler.
Start recording and do all interactions in the your app.
Stop recording and analyse where is the "tightest" place of your code.
Also check options "Invert call tree", "Hide missing symbols" and "Hide system libraries" for better viewing profile results.
You can also double click at any listed function to view it in code and seeing percents of usage

Swift function that takes in array giving error: '#lvalue $T24' is not identical to 'CGFloat'

So I'm writing a lowpass accelerometer function to moderate the jitters of the accelerometer. I have a CGFloat array to represent the data and i want to damp it with this function:
// Damps the gittery motion with a lowpass filter.
func lowPass(vector:[CGFloat]) -> [CGFloat]
{
let blend:CGFloat = 0.2
// Smoothens out the data input.
vector[0] = vector[0] * blend + lastVector[0] * (1 - blend)
vector[1] = vector[1] * blend + lastVector[1] * (1 - blend)
vector[2] = vector[2] * blend + lastVector[2] * (1 - blend)
// Sets the last vector to be the current one.
lastVector = vector
// Returns the lowpass vector.
return vector
}
In this case, lastVector is defined as follows up at the top of my program:
var lastVector:[CGFloat] = [0.0, 0.0, 0.0]
The three lines in the form vector[a] = ... give me the errors. Any ideas as to why i am getting this error?
That code seems to compile if you pass the array with the inout modifier:
func lowPass(inout vector:[CGFloat]) -> [CGFloat] {
...
}
I'm not sure whether that's a bug or not. Instinctively, if I pass an array to a function I expect to be able to modify it. If I pass with the inout modifier, I'd expect to be able to make the original variable to point to a new array - similar to what the & modifier does in C and C++.
Maybe the reason behind is that in Swift there are mutable and immutable arrays (and dictionaries). Without the inout it's considered immutable, hence the reason why it cannot be modified.
Addendum 1 - It's not a bug
#newacct says that's the intended behavior. After some research I agree with him. But even if not a bug I originally considered it wrong (read up to the end for conclusions).
If I have a class like this:
class WithProp {
var x : Int = 1
func SetX(newVal : Int) {
self.x = newVal
}
}
I can pass an instance of that class to a function, and the function can modify its internal state
var a = WithProp()
func Do1(p : WithProp) {
p.x = 5 // This works
p.SetX(10) // This works too
}
without having to pass the instance as inout.
I can use inout instead to make the a variable to point to another instance:
func Do2(inout p : WithProp) {
p = WithProp()
}
Do2(&a)
With that code, from within Do2 I make the p parameter (i.e. the a variable) point to a newly created instance of WithProp.
The same cannot be done with an array (and I presume a dictionary as well). To change its internal state (modify, add or remove an element) the inout modifier must be used. That was counterintuitive.
But everything gets clarified after reading this excerpt from the swift book:
Swift’s String, Array, and Dictionary types are implemented as structures. This means that strings, arrays, and dictionaries are copied when they are assigned to a new constant or variable, or when they are passed to a function or method.
So when passed to a func, it's not the original array, but a copy of it - Hence any change made to it (even if possible) wouldn't be done on the original array.
So, in the end, my original answer above is correct and the experienced behavior is not a bug
Many thanks to #newacct :)
Since Xcode 6 beta 3, modifying the contents of an Array is a mutating operation. You cannot modify a constant (i.e. let) Array; you can only modify a non-constant (i.e. var) Array.
Parameters to a function are constants by default. Therefore, you cannot modify the contents of vector since it is a constant. Like other parameters, there are two ways to be able to change a parameter:
Declare it var, in which case you can assign to it, but it is still passed by value, so any changes to the parameter has no effect on the calling scope.
Declare it inout, in which case the parameter is passed by reference, and any changes to the parameter is just like you made the changes on the variable in the calling scope.
You can see in the Swift standard library that all the functions that take an Array and mutate it, like sort(), take the Array as inout.
P.S. this is just like how arrays work in PHP by the way
Edit: The following worked for Xcode Beta 2. Apparently, the syntax and behavior of arrays has changed in Beta 3. You can no longer modify the contents of an array with subscripts if it is immutable (a parameter not declared inout or var):
Not valid with the most recent changes to the language
The only way I could get it to work in the play ground was change how you are declaring the arrays. I suggest trying this (works in playground):
import Cocoa
let lastVector: CGFloat[] = [0.0,0.0,0.0]
func lowPass(vector:CGFloat[]) -> CGFloat[] {
let blend: CGFloat = 0.2
vector[0] = vector[0] * blend + lastVector[0] * ( 1 - blend)
vector[1] = vector[1] * blend + lastVector[1] * ( 1 - blend)
vector[2] = vector[2] * blend + lastVector[2] * ( 1 - blend)
return vector
}
var test = lowPass([1.0,2.0,3.0]);
Mainly as a followup for future reference, #newacct's answer is the correct one. Since the original post showed a function that returns an array, the correct answer to this question is to tag the parameter with var:
func lowPass(var vector:[CGFloat]) -> [CGFloat] {
let blend:CGFloat = 0.2
// Smoothens out the data input.
vector[0] = vector[0] * blend + lastVector[0] * (1 - blend)
vector[1] = vector[1] * blend + lastVector[1] * (1 - blend)
vector[2] = vector[2] * blend + lastVector[2] * (1 - blend)
// Sets the last vector to be the current one.
lastVector = vector
// Returns the lowpass vector.
return vector
}

Randomizing pre-defined numbers

In my app I would like to randomize set values which I set in #define's. I am looking to use arc4random also. I usually would know how to do this but I have only seen tutorials with very basic things like numbers 0-10!
Any tips/help would be appreciated!
put all of your numbers to an array after that calculate an random number in range of 0 and sizeof your array. After you can get your randomized value from random place of predefined array and remove this value. Do it again for range 0 sizoef array - 1 and so on.
From the Wikipedia objective C article it looks like you can define macros using #define. From their example:
#define Add(x,y) ( x + y )
int a = 1;
int b = 2;
int c = Add(a,b);
NSLog(#"Add result: %i", c);
// this will output
// Add result: 3
I'm not sure how complex you can get with those, but I would think you'd be able to do something like #define MY_VAL() (arc4random()%100) to get a range of values, or maybe even use AlexTeho's idea within the macro.

Is there an easy way to compare how close two colors are to each other?

Is there a way to compare how close two colors are to each other? If to say both of them are blue.
At the moment the way that we compare them is to manually assign each possible color to a color family(red, green, blue...). And then just compare the strings :)
But surely that manual task can be assigned to a neat little algorithm.
You probably want to convert the colors to an HSL model (Hue, Saturation, Lightness) and then compare the values within thresholds in the order HSL. If the hue is within a tolerance deemed as "close", then check the "closeness" of the saturation, and then the lightness.
Delta-e, is a single number that represents the perceived 'distance' between two colors. The lower the number, the more similar the colors are to the human eye.
There are a few different ways to calculate it...CIE76 (aka CIE 1976 or dE76) being the most popular.
CIE76
CMC l:c
dE94
dE2000
Each one goes about things in a different way, but for the most part they all require you to convert to a better (for comparison) color model than RGB.
For CIE76 you basically just convert your colors to the LAB color space, then compute the 3 dimensional distance between them.
Wikipedia has all the formulae: http://en.wikipedia.org/wiki/Color_difference
You can check your work with online color calculators:
CIE76
CMC l:c
I'm not sure of any algorithms, you may want to consider converting RGB (Red, Green, Blue) values in to HSB (Hue, Saturation, Brightness).
Hue is essentially "color", so you can compare simply on how close the Hue values are.
See http://en.wikipedia.org/wiki/HSV_color_space
I know this question is 10 years old but extending Joe Zack's answer:
Here is my Kotlin code
//Entry point here
//Color must be hexa for example "#829381"
fun calculateColorDistance(colorA: String, colorB: String): Double {
val aColorRGBArray = getColorRGBArray(colorA)
val bColorRGBArray = getColorRGBArray(colorB)
val aColorLAB = getColorLab(aColorRGBArray)
val bColorLAB = getColorLab(bColorRGBArray)
return calculateColorDistance(aColorLAB, bColorLAB)
}
private fun calculateColorDistance(aColorLAB: DoubleArray, bColorLAB: DoubleArray): Double {
val lab = aColorLAB[0] - bColorLAB[0]
val aab = aColorLAB[1] - bColorLAB[1]
val bab = aColorLAB[2] - bColorLAB[2]
val sqrtlab = lab.pow(2)
val sqrtaab = aab.pow(2)
val sqrtbab = bab.pow(2)
val sum = sqrtlab + sqrtaab + sqrtbab
return sqrt(sum)
}
private fun getColorRGBArray(color: String): IntArray {
val cleanColor = color.replace("#", "")
val colorInt = Integer.parseInt(cleanColor, 16)
val r = Color.red(colorInt)
val g = Color.green(colorInt)
val b = Color.blue(colorInt)
return intArrayOf(r, g, b)
}
private fun getColorLab(colorRGB: IntArray): DoubleArray {
val outLab = doubleArrayOf(0.0,0.0,0.0)
ColorUtils.RGBToLAB(colorRGB[0], colorRGB[1], colorRGB[2], outLab)
return outLab
}
calculateColorDistance will return a Double value. the lower this value is the more similar the colors are.
Hope this helps someone

Resources