Ti - basic homography bilinear interpolation problem - ti-basic

I'm trying to make a program that can calculate bilinear interpolation with homography; which means I have four points (xn,yn) n = 1, 2, 3, 4, and corresponding f(xn, yn) and interpolate f(x,y) from the given four sets.
The basic concept is to get a homography matrix that moves four given (xn, yn) to the unit square, and to apply bilinear interpolation to the unit square.
https://math.stackexchange.com/questions/494238/how-to-compute-homography-matrix-h-from-corresponding-points-2d-2d-planar-homog (see Vishnu Pardeesh's answer)
https://en.wikipedia.org/wiki/Bilinear_interpolation
https://www.cs.ubc.ca/grads/resources/thesis/May09/Dubrofsky_Elan.pdf
And below is my Ti-basic code(including debugging codes)
Define LibPub blin()=
Prgm
:Request "x1",x1
:Request "y1",y1
:Request "f1",f1
:Request "x2",x2
:Request "y2",y2
:Request "f2",f2
:Request "x3",x3
:Request "y3",y3
:Request "f3",f3
:Request "x4",x4
:Request "y4",y4
:Request "f4",f4
:Request "x",x
:Request "y",y
:Local a
:a:=[[−x1,−y1,−1,0,0,0,0,0,0][0,0,0,−x1,−y1,−1,0,0,0][−x2,−y2,−1,0,0,0,x2,y2,1][0,0,0,−x2,−y2,−1,0,0,0][−x3,−y3,−1,0,0,0,x3,y3,1][0,0,0,−x3,−y3,−1,0,0,0][−x4,−y4,−1,0,0,0,x4,y4,1][0,0,0,−x4,−y4,−1,x4,y4,1][0,0,0,0,0,0,0,0,1]]
:Local b
:b:=[[0][0][0][0][0][0][0][0][1]]
:Local h
:h2:=(a*a)^(−1)*a*b
:Disp "h2 = ",h2
:Disp "b=a*h=",a*h2
:h:=[[h2[1,1],h2[2,1],h2[3,1]][h2[4,1],h2[5,1],h2[6,1]][h2[7,1],h2[8,1],h2[9,1]]]
:Disp "Homography h =",h
:Local q,q1,q2,q3,q4
:q:=h*[[x][y][1]]
:q1:=h*[[x1][y1][1]]
:q2:=h*[[x2][y2][1]]
:q3:=h*[[x3][y3][1]]
:q4:=h*[[x4][y4][1]]
:q:=((q)/(q[3,1]))
:q1:=((q1)/(q1[3,1]))
:q2:=((q2)/(q2[3,1]))
:q3:=((q3)/(q3[3,1]))
:q4:=((q4)/(q4[3,1]))
:Disp q,q1,q2,q3,q4
:Local f
:f:=[1-q[1,1],q[1,1]]*[[f1,f3][f2,f4]]*[[1-q[2,1]][q[2,1]]]
:Disp "f=",f
:Return f
:EndPrgm
And the testing result is like below.
x1 140
h2 =  [[−0.007144][0.182382][1.][7.70819−14][1.08176−12][−9.54405−12][−0.007144][0.182382][1.]]
b=a*h= [[1.77−11][−1.24859−12][1.57−11][−1.79793−12][1.86−11][−2.01942−12][1.78−11][−1.44315−12][1.]]
Homography h = [[−0.007144,0.182382,1.][7.70819−14,1.08176−12,−9.54405−12][−0.007144,0.182382,1.]]
[[1.][−3.2999−10][1.]] [[17.7][−1.24859][1.]] [[1.][1.94125−11][1.]] [[1.][−2.82671−11][1.]] [[−16.8][2.44315][1.]]
f= [2550.]
Since some fonts are breaking, I append screenshot here.
It seems the homography matrix does not move the given points to a unit square.
How can I fix the code?

It turns out that the order of the last three columns of the fifth and sixth row of the A has been changed.
thank you.

Related

Ruby: Round Down to Nearest Square Number

I want to create a class that makes the number round down to the nearest square number( 1, 4, 9, 16, 25...).
I've tried some other code suggestions but I haven't found anything helpful. I don't know mostly how to get it to the nearest square
class Integer
def down
#round down to nearest square using self
end
end
(27).down #=> 25
Josh, maybe the code below can help you. You can put that in a ruby file and then run in the terminal. It will ask for a value and will return the answer.
class Integer
def down
Integer.sqrt(self) ** 2
end
end
print "Enter a valid number: "
a = gets.to_i
puts a.down
Updated thanks to pjs and Cary Swoveland.

Convert floating-point number to words

How do I get the word-equivalent of a floating-point number? E.g.
10.24 → ten point twenty-four
5.113 → five point hundred and thirteen
There's a gem called numbers_and_words for that! I've used it in several projects without any problems so far.
Use the linguistics gem:
require 'linguistics'
Linguistics.use( :en )
p 10.24.en.numwords #=> "ten point two four"
p 5.113.en.numwords #=> "five point one one three"
or try to use this hack as described in this answer to get more precision:
require "linguistics"
Linguistics::use(:en)
class Float
def my_numwords
self.to_s.split('.').collect { |n| n.en.numwords }.join(' point ')
end
end
p 10.24.my_numwords #=> "ten point two four"
p 5.113.my_numwords #=> ""five point one hundred and thirteen"

iPart( and int( returning 0 for 1?

Ok, here's my problem. I wrote an advanced Pythagorean Theorem program, but it apparently is having exceptions. Here's an instance of my problem. When I input A? √(3) and B? 2, I get 0 back. Here's the code:
:Prompt A,C
:(C^2-A^2)->B
:If B<0
:Then
:Disp "THAT IS N
OT A VALID TRIA
ANGLE
:Else
:If iPart(√(B))≠
√(B)
:Then
:Disp "B = √(",B
:Else
:Disp "B = ",√(B)
:End
:End
Therefore, if B = 1, then hypothetically it should output B = 1 but instead it outputs:
A=? √(3)
C=? 2
B = √(
1
Done
What am I doing wrong and how can I fix it?
When I quickly evaluate your program, it seems to work correctly when you get B≠1. For example if I want to calculate the famous 3,4,5 - triangle it shows:
A=?4
C=?5
B=
3
Done
Apparently the iPart( doesn't work correctly with √(1). You could include an extra statement to the If iPart( ... statement to rule this out. Like this.
:...
:If iPart(√(B))≠√(B) and B≠1
:...
Besides that I think the program looks cleaner and nicer if you use the Input, ClrHome and Output( commands.
:ClrHome
:Input "A: ",A
:Input "C: ",C
:(C^2-A^2)->B
:If B<0
:Then
:Output(4,1,"THA
T IS NOT A")
:Output(5,1,"VAL
ID TRIANGLE")
:Else
:If iPart(√(B))≠
√(B) and B≠1
:Then
:Output(3,1,"B:
√( )")
:Output(3,5,B)
:Else
:Output(3,1,"B:")
:Output(3,5,√(B))
:End
:End
:Pause
:ClrHome
Now the results screen looks something like this:
A: √(3)
C: 2
B: 1
I think this is cleaner, with the 3 aligned istead of in the bottom right corner. When you press ENTER everything will remove itself from the screen (due to the Pause command).

Rock paper scissor - homework

In a game of rock-paper-scissors, each player chooses to play Rock (R), Paper (P), or Scissors (S). The rules are: Rock breaks Scissors, Scissors cuts Paper, but Paper covers Rock. In a round of rock-paper-scissors, each player's name and strategy is encoded as an array of two elements. Create a RockPaperScissors class with a class method winner that takes two 2-element arrays like those above, and returns the one representing the winner:
RockPaperScissors.winner(['Armando','P'], ['Dave','S']) # => ['Dave','S']
If either player's strategy is something other than "R", "P" or "S" (case-SENSITIVE), the method should raise a 'RockPaperScissors::NoSuchStrategyError' exception and provide the message: "Strategy must be one of R,P,S"
If both players use the same strategy, the first player is the winner.
I have my code below. My code is not comparing the two strings correctly in the line
(#p1[1,1]==rules["#{p}"]?#p1:#p2).
Please help me out.
class RockPaperScissors
def winner(p1,p2)
#p1 = p1
#p2 = p2
p = (#p1[1,1]+#p2[1,1]).sort
rules = Hash.new(0)
rules = {"PR"=>"R","PS"=>"S", "RS"=>"R", "PP"=>"1","RR"=>"1","SS"=>"1"}
if rules["#{p}"].nil?
raise RockPaperScissors::NoSuchStrategyError,"Strategy must be one of R,P,S"
elseif rules["#{p}"]=="1"
return #p1
else
print #p1[1,1]
print rules["#{p}"]
#p1[1,1]==rules["#{p}"]?#p1:#p2
end
end
end
t = RockPaperScissors.new
print t.winner(['Armando','R'], ['Dave','S'])
Some general tips: You don't need [1,1], [1] or .last would be better. Also no need to initialize rules to a new hash, you can only keep the line rules = {"PR"=>"R".... puts is more commonly used than print. You're overthinking this a bit. Maybe clean up your code, try to simplify it with the tips posted above and see if this gets you unstuck.
Once you are done, have a look at what an idiomatic Ruby solution could look like, but don't submit it as your solution:
module RockPaperScissors
VALID_STRATEGIES = %i(R P S)
RULES = { R: :S, P: :R, S: :P }
def self.winner(p1, p2)
choice1, choice2 = p1.last.intern, p2.last.intern
unless [choice1, choice2].all? { |s| VALID_STRATEGIES.include? s }
raise RockPaperScissors::NoSuchStrategyError, "Strategy must be one of R,P,S"
end
return p1 if choice1 == choice2
RULES[choice1] == choice2 ? p1 : p2
end
end
When you use the [1,1] on an array, you receive an array of size 1 starting from index 1:
[1,2,3][1,1]
# => [2]
[1,2,3][1]
# => 2
Because of that when you compare it to the rules, you never get true, since no rule is an array...
["S"] == "S"
# => false
So to fix your code, instead of
p = (#p1[1,1]+#p2[1,1]).sort
# ...
(#p1[1,1]==rules["#{p}"]?#p1:#p2)
You should try:
p = (#p1[1]+#p2[1]).sort
# ...
(#p1[1]==rules[p]?#p1:#p2

How to return a Ruby array intersection with duplicate elements? (problem with bigrams in Dice Coefficient)

I'm trying to script Dice's Coefficient, but I'm having a bit of a problem with the array intersection.
def bigram(string)
string.downcase!
bgarray=[]
bgstring="%"+string+"#"
bgslength = bgstring.length
0.upto(bgslength-2) do |i|
bgarray << bgstring[i,2]
end
return bgarray
end
def approx_string_match(teststring, refstring)
test_bigram = bigram(teststring) #.uniq
ref_bigram = bigram(refstring) #.uniq
bigram_overlay = test_bigram & ref_bigram
result = (2*bigram_overlay.length.to_f)/(test_bigram.length.to_f+ref_bigram.length.to_f)*100
return result
end
The problem is, as & removes duplicates, I get stuff like this:
string1="Almirante Almeida Almada"
string2="Almirante Almeida Almada"
puts approx_string_match(string1, string2) => 76.0%
It should return 100.
The uniq method nails it, but there is information loss, which may bring unwanted matches in the particular dataset I'm working.
How can I get an intersection with all duplicates included?
As Yuval F said you should use multiset. However, there is nomultiset in Ruby standard library , Take at look at here and here.
If performance is not that critical for your application, you still can do it usingArray with a little bit code.
def intersect a , b
a.inject([]) do |intersect, s|
index = b.index(s)
unless index.nil?
intersect << s
b.delete_at(index)
end
intersect
end
end
a= ["al","al","lc" ,"lc","ld"]
b = ["al","al" ,"lc" ,"ef"]
puts intersect(a ,b).inspect #["al", "al", "lc"]
From this link I believe you should not use Ruby's sets but rather multisets, so that every bigram gets counted the number of times it appears. Maybe you can use this gem for multisets. This should give a correct behavior for recurring bigrams.
I toyed with this, based on the answer from #pierr, for a while and ended up with this.
a = ["al","al","lc","lc","lc","lc","ld"]
b = ["al","al","al","al","al","lc","ef"]
result=[]
h1,h2=Hash.new(0),Hash.new(0)
a.each{|x| h1[x]+=1}
b.each{|x| h2[x]+=1}
h1.each_pair{|key,val| result<<[key]*[val,h2[key]].min if h2[key]!=0}
result.flatten
=> ["al", "al", "lc"]
This could be a kind of multiset intersect of a & b but don't take my word for it because I haven't tested it enough to be sure.

Resources