Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.awt.Color;
- import java.awt.Frame;
- import java.awt.Graphics;
- import java.awt.event.WindowAdapter;
- import java.awt.event.WindowEvent;
- import java.awt.image.BufferedImage;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import javax.imageio.ImageIO;
- import javax.sound.sampled.AudioFileFormat;
- import javax.sound.sampled.AudioFormat;
- import javax.sound.sampled.AudioInputStream;
- import javax.sound.sampled.AudioSystem;
- import javax.sound.sampled.SourceDataLine;
- public class GramProcessor {
- private final static AudioFormat af = new AudioFormat((float) 16000, 8, 1, false,
- false);
- // this variables are used to control ui position while debugging
- private static final float zoom = 2.5f;
- private final int yoff = -00;
- private final int xoff = -00;
- // this are some good constants
- private static final int widthWindowSize = 5;
- private static final int threshold = 180;
- private static final float angleStep = (float) (Math.PI / 4000);
- private Frame f = new Frame("window");
- private Graphics g;
- private float radius; // current position
- private float angle = 0;
- private int numBad = 0; // this variable contains number of possibly
- // non-track
- // points we've found. if we're off-the-track too long it
- // means track has ended
- int faithSteps = 0; // number of steps we've done since last needle setup.
- float lastGoodAngle; // last angle we've found that what is definitely track
- public static void main(String[] args) throws Exception {
- if (args.length < 1) {
- System.err.println("wrong args");
- System.exit(1);
- }
- BufferedImage img = ImageIO.read(new File(args[0]));
- byte[] raw = new GramProcessor().process(img);
- AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(raw), af, raw.length), AudioFileFormat.Type.WAVE, new File(args[0] + ".wav"));
- }
- /**
- * processes image
- * @param img image to process
- * @return raw PCM in af format
- * @throws Exception
- */
- public byte[] process(BufferedImage img) throws Exception {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- f.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- System.exit(0);
- }
- });
- // initializing audio engine... 16000 khz looks good enough
- SourceDataLine sdl = AudioSystem.getSourceDataLine(af);
- sdl.open(af);
- sdl.start();
- int xsize = img.getWidth();
- int ysize = img.getHeight();
- int xmid = xsize / 2;
- int ymid = ysize / 2;
- f.setSize((int) (xsize / zoom), (int) (ysize / zoom));
- f.setVisible(true);
- g = f.getGraphics();
- g.setColor(Color.RED);
- g.drawImage(img, xoff, yoff, (int) (xsize / zoom),
- (int) (ysize / zoom), null);
- int trackY;
- // here we are going down in the center of the image searching for point
- // of track. we get medium point of first track we find
- {
- boolean inTrack = false;
- int trackYStart = -1, trackYEnd = -1;
- for (int y = 0; y < ysize; y++) {
- if (getWhiteness(img, xmid, y, true) > threshold) {
- inTrack = true;
- if (trackYStart < 0) {
- trackYStart = y;
- }
- } else if (inTrack) {
- trackYEnd = y - 1;
- break;
- }
- }
- trackY = (trackYStart + trackYEnd) / 2;
- }
- // so now we at topmost position of outer track
- angle = 0;
- radius = ymid - trackY;
- numBad = 0;
- // let's roll clockwise to find track's beginning
- while (numBad < 4) {
- doStep(-1, img, xmid, ymid, false);
- }
- angle += 4 * angleStep;
- lastGoodAngle = angle;
- faithSteps = 0;
- numBad = 0;
- // no we read track counter-clockwise till the end
- while (numBad < 35) {
- int wb = doStep(1, img, xmid, ymid, true);
- // and play bytes we've read
- sdl.write(new byte[] { (byte) (wb) }, 0, 1);
- out.write(wb);
- }
- // stopping audio engine
- sdl.drain();
- sdl.stop();
- sdl.close();
- return out.toByteArray();
- }
- /**
- * this function makes step on the track and corrects needle position if needed
- *
- * @param sign
- * if negative, CW, otherwise CCW
- * @param img
- * img we read
- * @param xmid
- * image center
- * @param ymid
- * image center
- * @param doVisualisation
- * marks if we must display progress in UI
- * @return byte we've read on this step
- */
- private byte doStep(int sign, BufferedImage img, int xmid, int ymid,
- boolean doVisualisation) {
- angle += Math.signum(sign) * angleStep;
- faithSteps++;
- int wtn = getWhiteness(img, xmid, ymid, radius, angle, doVisualisation);
- if (wtn > threshold) {
- lastGoodAngle = angle;
- }
- if ((wtn < threshold) || (faithSteps > 50)) {
- // we may need to correct the needle: we're off-the track or we're
- // on the track too long and we may read blurred pixels near track
- // edge.
- float delta = 0;
- int iterationsNum = 3;
- int goodIterationsNum = 0;
- // so we go to last point we knew we're on the track and find
- // track's middle point at that angle. We do this for some angles
- // before this angle too cause there are artifacts sometimes
- for (int i = 0; i < iterationsNum; i++) {
- float windowMinGood = -1;
- float windowMaxGood = -1;
- faithSteps = 0;
- // finding track middle point is easy: we vary current radius
- // and see if we're on track or not
- for (int windowIterator = 0; windowIterator < widthWindowSize * 2; windowIterator++) {
- int probe = getWhiteness(img, xmid, ymid, radius
- - widthWindowSize + windowIterator, lastGoodAngle
- - i * angleStep, doVisualisation);
- if (probe > threshold) {
- if (windowMinGood < 0)
- windowMinGood = windowIterator;
- windowMaxGood = windowIterator;
- } else if (windowMaxGood >= 0) {
- break;
- }
- }
- if (windowMaxGood > 0) { // we've found track, let's add it's
- // actual radius
- delta += (windowMinGood + windowMaxGood) / 2;
- goodIterationsNum++;
- }
- }
- if (goodIterationsNum > 0)
- radius = radius - widthWindowSize + delta / goodIterationsNum;
- wtn = getWhiteness(img, xmid, ymid, radius, angle, doVisualisation);
- numBad++;
- } else {
- numBad = 0;
- }
- return (byte) (wtn);
- }
- /**
- * this function gets brightness value by radial coords
- *
- * @param img
- * @param xmid
- * @param ymid
- * @param radius
- * @param angle
- * @param doVisualisation
- * @return
- */
- private int getWhiteness(BufferedImage img, int xmid, int ymid,
- float radius, float angle, boolean doVisualisation) {
- int x = (int) (xmid - radius * Math.sin(angle));
- int y = (int) (ymid - radius * Math.cos(angle));
- return getWhiteness(img, x, y, doVisualisation);
- }
- /**
- * this function gets brightness value by decart coords
- *
- * @param img
- * @param xi
- * @param yi
- * @param doVisualisation
- * @return
- */
- private int getWhiteness(BufferedImage img, int xi, int yi,
- boolean doVisualisation) {
- int res = img.getRGB(xi, yi) & 0xff;
- if (doVisualisation) {
- if (res > threshold)
- g.setColor(Color.GREEN);
- else
- g.setColor(Color.RED);
- g.drawLine((int) (xi / zoom) + xoff, (int) (yi / zoom) + yoff,
- (int) (xi / zoom) + xoff, (int) (yi / zoom) + yoff);
- }
- return res;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement