September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -5,22 +5,30 @@ import qualified Data.Foldable as F (maximum)
import System.Environment (getArgs, getProgName)
-- Library JuicyPixels:
import Codec.Picture (DynamicImage(ImageRGB8, ImageRGBA8), Image,
PixelRGB8(PixelRGB8), PixelRGBA8(PixelRGBA8),
imageWidth, imageHeight, pixelAt, generateImage,
readImage, pixelMap, savePngImage)
import Codec.Picture
(DynamicImage(ImageRGB8, ImageRGBA8), Image, PixelRGB8(PixelRGB8),
PixelRGBA8(PixelRGBA8), imageWidth, imageHeight, pixelAt,
generateImage, readImage, pixelMap, savePngImage)
import Codec.Picture.Types (extractLumaPlane, dropTransparency)
dot :: Num a => (a, a) -> (a, a) -> a
dot
:: Num a
=> (a, a) -> (a, a) -> a
dot (x1, y1) (x2, y2) = x1 * x2 + y1 * y2
mag :: Floating a => (a, a) -> a
mag
:: Floating a
=> (a, a) -> a
mag a = sqrt $ dot a a
sub :: Num a => (a, a) -> (a, a) -> (a, a)
sub
:: Num a
=> (a, a) -> (a, a) -> (a, a)
sub (x1, y1) (x2, y2) = (x1 - x2, y1 - y2)
fromIntegralP :: (Integral a, Num b) => (a, a) -> (b, b)
fromIntegralP
:: (Integral a, Num b)
=> (a, a) -> (b, b)
fromIntegralP (x, y) = (fromIntegral x, fromIntegral y)
{-
@ -39,63 +47,59 @@ hough image thetaSize distSize = hImage
hMax = height - 1
xCenter = wMax `div` 2
yCenter = hMax `div` 2
lumaMap = extractLumaPlane image
gradient x y =
let orig = pixelAt lumaMap x y
x' = pixelAt lumaMap (min (x + 1) wMax) y
y' = pixelAt lumaMap x (min (y + 1) hMax)
in fromIntegralP (orig - x', orig - y')
gradMap = [((x, y), gradient x y) | x <- [0..wMax], y <- [0..hMax]]
x_ = pixelAt lumaMap (min (x + 1) wMax) y
y_ = pixelAt lumaMap x (min (y + 1) hMax)
in fromIntegralP (orig - x_, orig - y_)
gradMap =
[ ((x, y), gradient x y)
| x <- [0 .. wMax]
, y <- [0 .. hMax] ]
-- The longest distance from the center, half the hypotenuse of the image.
distMax :: Double
distMax = (sqrt . fromIntegral $ height ^ 2 + width ^ 2) / 2
{-
The accumulation bins of the polar values.
For each value in the gradient image, if the gradient length exceeds
some threshold, consider it evidence of a line and plot all of the
lines that go through that point in Hough space.
-}
accBin = runSTArray $ do
arr <- newArray ((0, 0), (thetaSize, distSize)) 0
forM_ gradMap $ \((x, y), grad) -> do
let (x', y') = fromIntegralP $ (xCenter, yCenter) `sub` (x, y)
when (mag grad > 127) $
forM_ [0..thetaSize] $ \theta -> do
let theta' = (fromIntegral theta) * 360 / (fromIntegral thetaSize)
/ 180 * pi :: Double
dist = (cos theta' * x' + sin theta' * y')
dist' = truncate $ dist * (fromIntegral distSize) / distMax
idx = (theta, dist')
when (dist' >= 0 && dist' < distSize) $ do
old <- readArray arr idx
writeArray arr idx $ old + 1
return arr
accBin =
runSTArray $
do arr <- newArray ((0, 0), (thetaSize, distSize)) 0
forM_ gradMap $
\((x, y), grad) -> do
let (x_, y_) = fromIntegralP $ (xCenter, yCenter) `sub` (x, y)
when (mag grad > 127) $
forM_ [0 .. thetaSize] $
\theta -> do
let theta_ =
fromIntegral theta * 360 / fromIntegral thetaSize / 180 *
pi :: Double
dist = cos theta_ * x_ + sin theta_ * y_
dist_ = truncate $ dist * fromIntegral distSize / distMax
idx = (theta, dist_)
when (dist_ >= 0 && dist_ < distSize) $
do old <- readArray arr idx
writeArray arr idx $ old + 1
return arr
maxAcc = F.maximum accBin
-- The image representation of the accumulation bins.
hTransform x y =
let l = 255 - (truncate $ (accBin ! (x, y)) / maxAcc * 255)
let l = 255 - truncate ((accBin ! (x, y)) / maxAcc * 255)
in PixelRGB8 l l l
hImage = generateImage hTransform thetaSize distSize
houghIO :: FilePath -> FilePath -> Int -> Int -> IO ()
houghIO path outpath thetaSize distSize = do
image <- readImage path
case image of
Left err -> putStrLn err
Right (ImageRGB8 image') -> doImage image'
Right (ImageRGBA8 image') -> doImage $ pixelMap dropTransparency image'
_ -> putStrLn $ "Expecting RGB8 or RGBA8 image"
Left err -> putStrLn err
Right (ImageRGB8 image_) -> doImage image_
Right (ImageRGBA8 image_) -> doImage $ pixelMap dropTransparency image_
_ -> putStrLn "Expecting RGB8 or RGBA8 image"
where
doImage image = do
let houghImage = hough image thetaSize distSize
@ -108,4 +112,6 @@ main = do
case args of
[path, outpath, thetaSize, distSize] ->
houghIO path outpath (read thetaSize) (read distSize)
_ -> putStrLn $ "Usage: " ++ prog ++ " <image-file> <out-file.png> <width> <height>"
_ ->
putStrLn $
"Usage: " ++ prog ++ " <image-file> <out-file.png> <width> <height>"

View file

@ -1,3 +1,4 @@
require 'viewmat media/platimg'
Img=: readimg jpath '~temp/pentagon.png'
require 'viewmat'
require 'media/platimg' NB. addon required pre J8
Img=: readimg_jqtide_ jpath '~temp/pentagon.png'
viewmat 460 360 houghTransform _1 > Img

View file

@ -1,11 +1,10 @@
import java.awt.image.*
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.*
import javax.imageio.ImageIO
internal class ArrayData(val dataArray: IntArray, val width: Int, val height: Int) {
constructor(width: Int, height: Int) : this(IntArray(width * height), width, height) {
}
constructor(width: Int, height: Int) : this(IntArray(width * height), width, height)
operator fun get(x: Int, y: Int) = dataArray[y * width + x]

View file

@ -0,0 +1,17 @@
const WHITE=0xffFFff, X=0x010101;
fcn houghTransform(image,hx=460,hy=360){
if(hy.isOdd) hy-=1; // hy argument must be even
out:=PPM(hx,hy,WHITE);
rMax:=image.w.toFloat().hypot(image.h);
dr,dTh:=rMax/(hy/2), (0.0).pi/hx;
foreach y,x in (image.h,image.w){
if(image[x,y]==WHITE) continue;
foreach iTh in (hx){
th,r:=dTh*iTh, th.cos()*x + th.sin()*y;
iry:=hy/2 + (r/dr + 0.5).floor(); // y==0 is top
if(out[iTh,iry]>0) out[iTh,iry]=out[iTh,iry] - X;
}
}
out
}

View file

@ -0,0 +1,8 @@
fcn readPNG2PPM(fileName){
p:=System.popen("convert \"%s\" ppm:-".fmt(fileName),"r");
img:=PPM.readPPM(p);
p.close();
img
}
houghTransform(readPNG2PPM("pentagon.png"))
.write(File("pentagon_hough.ppm","wb"));