Bilinear interpolation: Difference between revisions
m
→{{header|Wren}}: ImageData.loadFromFile now deprecated, changed to ImageData.load
m (→{{header|Wren}}: ImageData.loadFromFile now deprecated, changed to ImageData.load) |
|||
(11 intermediate revisions by 6 users not shown) | |||
Line 3:
[[wp:Bilinear interpolation|Bilinear interpolation]] is linear interpolation in 2 dimensions, and is typically used for image scaling and for 2D finite element analysis.
;Task:
Open an image file, enlarge it by 60% using bilinear interpolation, then either display the result or save the result to a file.
<br><br>
=={{header|Action!}}==
In the following solution the input file [https://gitlab.com/amarok8bit/action-rosetta-code/-/blob/master/source/lena30g.PPM lena30g.PPM] is loaded from H6 drive. Altirra emulator automatically converts CR/LF character from ASCII into 155 character in ATASCII charset used by Atari 8-bit computer when one from H6-H10 hard drive under DOS 2.5 is used.
{{libheader|Action! Bitmap tools}}
{{libheader|Action! Tool Kit}}
{{libheader|Action! Real Math}}
<syntaxhighlight lang="action!">INCLUDE "H6:REALMATH.ACT"
INCLUDE "H6:LOADPPM5.ACT"
PROC PutBigPixel(INT x,y BYTE col)
IF x>=0 AND x<=79 AND y>=0 AND y<=47 THEN
y==LSH 2
col==RSH 4
IF col<0 THEN col=0
ELSEIF col>15 THEN col=15 FI
Color=col
Plot(x,y)
DrawTo(x,y+3)
FI
RETURN
PROC DrawImage(GrayImage POINTER image INT x,y)
INT i,j
BYTE c
FOR j=0 TO image.gh-1
DO
FOR i=0 TO image.gw-1
DO
c=GetGrayPixel(image,i,j)
PutBigPixel(x+i,y+j,c)
OD
OD
RETURN
PROC Lerp(REAL POINTER s,e,t,res)
REAL tmp1,tmp2
RealSub(e,s,tmp1) ;tmp1=e-s
RealMult(tmp1,t,tmp2) ;tmp2=(e-s)*t
RealAdd(s,tmp2,res) ;res=s+(e-s)*t
RETURN
PROC BilinearInterpolation(GrayImage POINTER src,dst)
INT i,j,x,y,c
REAL mx,my,rx,ry,fx,fy,tmp1,tmp2,tmp3,r00,r01,r10,r11
BYTE c00,c01,c10,c11
IntToReal(src.gw-1,tmp1) ;tmp1=src.width-1
IntToReal(dst.gw,tmp2) ;tmp2=dst.width
RealDiv(tmp1,tmp2,mx) ;mx=(src.width-1)/dst.width
IntToReal(src.gh-1,tmp1) ;tmp1=src.height-1
IntToReal(dst.gh,tmp2) ;tmp2=dst.height
RealDiv(tmp1,tmp2,my) ;my=(src.height-1)/dst.height
FOR j=0 TO dst.gh-1
DO
IntToReal(j,tmp1) ;tmp=j
RealMult(tmp1,my,ry) ;ry=j*my
y=Floor(ry)
IntToReal(y,tmp1) ;tmp1=floor(ry)
RealSub(ry,tmp1,fy) ;fy=frac(ry)
FOR i=0 TO dst.gw-1
DO
IntToReal(i,tmp1) ;tmp=i
RealMult(tmp1,mx,rx) ;rx=i*mx
x=Floor(rx)
IntToReal(x,tmp1) ;tmp1=floor(rx)
RealSub(rx,tmp1,fx) ;fx=frac(rx)
c00=GetGrayPixel(src,x,y)
c01=GetGrayPixel(src,x,y+1)
c10=GetGrayPixel(src,x+1,y)
c11=GetGrayPixel(src,x+1,y+1)
IntToReal(c00,r00)
IntToReal(c01,r01)
IntToReal(c10,r10)
IntToReal(c11,r11)
Lerp(r00,r10,fx,tmp1)
Lerp(r01,r11,fx,tmp2)
Lerp(tmp1,tmp2,fy,tmp3)
c=RealToInt(tmp3)
IF c<0 THEN
c=0
ELSEIF c>255 THEN
c=255
FI
SetGrayPixel(dst,i,j,c)
OD
OD
RETURN
PROC Main()
BYTE CH=$02FC ;Internal hardware value for last key pressed
BYTE ARRAY data30x30(900),data48x48(2304)
GrayImage im30x30,im48x48
Put(125) PutE() ;clear the screen
MathInit()
InitGrayImage(im30x30,30,30,data30x30)
InitGrayImage(im48x48,48,48,data48x48)
PrintE("Loading source image...")
LoadPPM5(im30x30,"H6:LENA30G.PPM")
PrintE("Bilinear interpolation...")
BilinearInterpolation(im30x30,im48x48)
Graphics(9)
DrawImage(im30x30,0,0)
DrawImage(im48x48,32,0)
DO UNTIL CH#$FF OD
CH=$FF
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Bilinear_interpolation.png Screenshot from Atari 8-bit computer]
=={{header|C}}==
<
typedef struct {
uint32_t *pixels;
Line 55 ⟶ 170:
putpixel(dst,x, y, result);
}
}</
=={{header|C sharp|C#}}==
{{trans|Java}}
Seems to have some artifacting in the output, but the image is at least recognizable.
<
using System.Drawing;
Line 110 ⟶ 224:
}
}
}</
=={{header|D}}==
This uses the module from the Grayscale Image task.
{{trans|C}}
<
/// Currently this accepts only a Grayscale image, for simplicity.
Line 163 ⟶ 276:
im.rescaleGray(0.3, 0.1).savePGM("lena_smaller.pgm");
im.rescaleGray(1.3, 1.8).savePGM("lena_larger.pgm");
}</
=={{header|F sharp|F#}}==
{{trans|C#}}
<
open System.Drawing
Line 213 ⟶ 325:
result.Save("Lenna100_larger.jpg")
0 // return an integer exit code</
=={{header|Go}}==
{{trans|C}}
Line 220 ⟶ 331:
<code>[https://godoc.org/golang.org/x/image/draw#BiLinear draw.BiLinear]</code>
from the <code>golang.org/x/image/draw</code> pacakge).
<
import (
Line 312 ⟶ 423:
}
return err
}</
=={{header|J}}==
<syntaxhighlight lang="j">
Note 'FEA'
Here we develop a general method to generate isoparametric interpolants.
Line 377 ⟶ 487:
shape_functions =: COEFFICIENTS mp~ shape_function
interpolate =: mp shape_functions
</syntaxhighlight>
<pre>
Note 'demonstrate the interpolant with a saddle'
Line 396 ⟶ 506:
Let n mean shape function, C mean constants, i mean interpolant, and the three digits meaning dimensionality, number of corners, and (in base 36) the number of nodes we construct various linear and quadratic interpolants in 1, 2, and 3 dimensions as
<syntaxhighlight lang="j">
Note 'Some elemental information'
Line 492 ⟶ 602:
i38q =: mp (C38r mp~ n38r)
i38r =: mp (C38r mp~ n38r)
</syntaxhighlight>
=={{header|Java}}==
{{trans|Kotlin}}
<
import java.awt.image.BufferedImage;
import java.io.File;
Line 551 ⟶ 660:
ImageIO.write(image2, "jpg", lenna2);
}
}</
=={{header|Julia}}==
<
function enlarge(A::Matrix, factor::AbstractFloat)
Line 567 ⟶ 675:
Alarge = enlarge(A, 1.6);
save("data/lennaenlarged.jpg", Alarge)
</syntaxhighlight>
=={{header|Kotlin}}==
{{trans|C}}
<
import java.io.File
Line 620 ⟶ 727:
val lenna2 = File("Lenna100_larger.jpg")
ImageIO.write(image2, "jpg", lenna2)
}</
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ImageResize[Import["http://www.rosettacode.org/mw/title.png"], Scaled[1.6], Resampling -> "Linear"]</syntaxhighlight>
{{out}}
Shows a downloaded image that is 60% enlarged.
=={{header|Nim}}==
{{trans|F#}}
{{libheader|imageman}}
<
func lerp(s, e, t: float): float =
Line 658 ⟶ 768:
let image = loadImage[ColorRGBU]("Lenna100.jpg")
let newImage = image.scale(1.6, 1.6)
newImage.saveJPEG("Lenna100_bilinear.jpg")</
=={{header|Perl}}==
<
use warnings;
Line 671 ⟶ 780:
my $image2 = $image->copyScaleInterpolated( 1.6*$width, 1.6*$height );
$image2->_file('color_wheel_interpolated.png');</
Compare offsite images: [https://github.com/SqrtNegInf/Rosettacode-Perl5-Smoke/blob/master/ref/color_wheel.png color_wheel.png] vs.
[https://github.com/SqrtNegInf/Rosettacode-Perl5-Smoke/blob/master/ref/color_wheel_interpolated.png color_wheel_interpolated.png]
=={{header|Phix}}==
{{libheader|Phix/pGUI}}
Gui app with slider for between 2 and 200% scaling. Various bits of this code scavenged from C#/Go/Kotlin/Wikipedia.
<
include pGUI.e
Line 801 ⟶ 909:
IupMainLoop()
IupClose()</
=={{header|Python}}==
Of course, it is much faster to use PIL, Pillow or SciPy to resize an image than to rely on this code.
<
import numpy as np
from scipy.misc import imread, imshow
Line 853 ⟶ 960:
imshow(enlargedImg)
</syntaxhighlight>
=={{header|Racket}}==
This mimics the Wikipedia example.
<
(require images/flomap)
Line 878 ⟶ 984:
(λ (k x y)
(flomap-bilinear-ref
fm k (+ 1/2 (/ x 250)) (+ 1/2 (/ y 250))))))</
=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku"
use v6;
Line 912 ⟶ 1,017:
fclose($fh1);
fclose($fh2);
</syntaxhighlight>
{{out}}
Line 918 ⟶ 1,023:
Lenna100.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 512x512, frames 3
Lenna100-larger.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, comment: "CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), default quality", baseline, precision 8, 820x820, frames 3</pre>
=={{header|Scala}}==
===Imperative solution===
<
import java.io.{File, IOException}
Line 979 ⟶ 1,083:
private def lerp(s: Float, e: Float, t: Float) = s + (e - s) * t
}</
=={{header|Sidef}}==
{{trans|C}}
<
func scale(img, scaleX, scaleY) {
Line 1,023 ⟶ 1,126:
var img = %O<Imager>.new(file => "input.png")
var out = scale(img, 1.6, 1.6)
out.write(file => "output.png")</
=={{header|Tcl}}==
Line 1,031 ⟶ 1,133:
The script below will show the computed image in a GUI frame, and present a button to save it.
<syntaxhighlight lang="tcl">
package require Tk
Line 1,076 ⟶ 1,178:
pack [button .b -text "save" -command [list save $im]]
</syntaxhighlight>
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<
Module Module1
Line 1,131 ⟶ 1,232:
End Sub
End Module</
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|DOME}}
Note that currently DOME's ImageData class can only save files to disk in .png format.
<syntaxhighlight lang="wren">import "dome" for Window
import "graphics" for Canvas, Color, ImageData
import "math" for Math
/* gets the 'n'th byte of a 4-byte integer */
var GetByte = Fn.new { |i, n| (i >> (n * 8)) & 0xff }
var Blerp = Fn.new { |c00, c10, c01, c11, tx, ty|
return Math.lerp(Math.lerp(c00, tx, c10), ty, Math.lerp(c01, tx, c11))
}
var ColorToInt = Fn.new { |c| (c.r) + (c.g << 8) + (c.b << 16) + (c.a << 24) }
class BilinearInterpolation {
construct new(filename, filename2, scaleX, scaleY) {
Window.title = "Bilinear interpolation"
_img = ImageData.load(filename)
var newWidth = (_img.width * scaleX).floor
var newHeight = (_img.height * scaleY).floor
Window.resize(newWidth, newHeight)
Canvas.resize(newWidth, newHeight)
_img2 = ImageData.create(filename2, newWidth, newHeight)
_filename2 = filename2
}
init() {
scaleImage()
}
scaleImage() {
for (x in 0..._img2.width) {
for (y in 0..._img2.height) {
var gx = x / _img2.width * (_img.width - 1)
var gy = y / _img2.height * (_img.height - 1)
var gxi = gx.floor
var gyi = gy.floor
var rgb = 0
var c00 = _img.pget(gxi, gyi)
var c10 = _img.pget(gxi+1, gyi)
var c01 = _img.pget(gxi, gyi+1)
var c11 = _img.pget(gxi+1, gyi+1)
for (i in 0..3) {
var b00 = GetByte.call(ColorToInt.call(c00), i)
var b10 = GetByte.call(ColorToInt.call(c10), i)
var b01 = GetByte.call(ColorToInt.call(c01), i)
var b11 = GetByte.call(ColorToInt.call(c11), i)
var ble = Blerp.call(b00, b10, b01, b11, gx-gxi, gy-gyi).floor << (8 * i)
rgb = rgb | ble
}
var r = GetByte.call(rgb, 0)
var g = GetByte.call(rgb, 1)
var b = GetByte.call(rgb, 2)
var a = GetByte.call(rgb, 3)
_img2.pset(x, y, Color.rgb(r, g, b, a))
}
}
_img2.draw(0, 0)
_img2.saveToFile(_filename2)
}
update() {}
draw(alpha) {}
}
var Game = BilinearInterpolation.new("Lenna100.jpg", "Lenna100_larger.png", 1.6, 1.6)</syntaxhighlight>
=={{header|Yabasic}}==
{{trans|Nim}}
<syntaxhighlight lang="yabasic">// Rosetta Code problem: http://rosettacode.org/wiki/Bilinear_interpolation
// Adapted from Nim to Yabasic by Galileo, 01/2022
import ReadFromPPM2
sub lerp(s, e, t)
return s + (e - s) * t
end sub
sub blerp(c00, c10, c01, c11, tx, ty)
return lerp(lerp(c00, c10, tx), lerp(c01, c11, tx), ty)
end sub
sub scale(scaleX, scaleY)
local width, height, x, y, gx, gy, gxi, gyi, gxf, gyf, c00$, c10$, c01$, c11$
width = peek("winwidth")
height = peek("winheight")
let newWidth = int(width * scaleX)
let newHeight = int(height * scaleY)
dim result(newWidth, newHeight, 3)
for x = 1 to newWidth
for y = 1 to newHeight:
let gx = x * (width - 1) / newWidth
let gy = y * (height - 1) / newHeight
let gxi = int(gx)
let gyi = int(gy)
let gxf = gx - gxi
let gyf = gy - gyi
let c00$ = right$(getbit$(gxi, gyi, gxi, gyi), 6)
let c10$ = right$(getbit$(gxi + 1, gyi, gxi + 1, gyi), 6)
let c01$ = right$(getbit$(gxi, gyi + 1, gxi, gyi + 1), 6)
let c11$ = right$(getbit$(gxi + 1, gyi + 1, gxi + 1, gyi + 1), 6)
result(x, y, 1) = int(blerp(dec(left$(c00$, 2)), dec(left$(c10$, 2)), dec(left$(c01$, 2)), dec(left$(c11$, 2)), gxf, gyf))
result(x, y, 2) = int(blerp(dec(mid$(c00$, 3, 2)), dec(mid$(c10$, 3, 2)), dec(mid$(c01$, 3, 2)), dec(mid$(c11$, 3, 2)), gxf, gyf))
result(x, y, 3) = int(blerp(dec(right$(c00$, 2)), dec(right$(c10$, 2)), dec(right$(c01$, 2)), dec(right$(c11$, 2)), gxf, gyf))
next
next
end sub
readPPM("lena.ppm")
print "Be patient, please ..."
scale(1.6, 1.6)
close window
open window newWidth, newHeight
for x = 1 to newWidth
for y = 1 to newHeight
color result(x, y, 1), result(x, y, 2), result(x, y, 3)
dot x, y
next
next</syntaxhighlight>
=={{header|zkl}}==
{{trans|C}}
Line 1,138 ⟶ 1,363:
Not fast enough to be called slow.
<
fcn blerp(c00,c10,c01,c11, tx,ty){ lerp(lerp(c00,c10,tx), lerp(c01,c11,tx),ty) }
fcn scale(src, scaleX,scaleY){
Line 1,158 ⟶ 1,383:
}
dst
}</
<
img2:=scale(img,1.5,1.5);
img2.write(File("lena1.5.ppm","wb"));
scale(img,0.5,0.5).write(File("lena.5.ppm","wb"));</
{{out}}
http://www.zenkinetic.com/Images/RosettaCode/3Lenas.jpg
|