kopia lustrzana https://github.com/xdsopl/robot36
Detecting white margin in HF Fax mode and correcting image shift when saving
rodzic
9558080ff8
commit
638484ae78
|
@ -1,4 +1,8 @@
|
|||
package xdsopl.robot36;
|
||||
|
||||
public abstract class BaseMode implements Mode {
|
||||
@Override
|
||||
public int getEstimatedHorizontalShift() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
package xdsopl.robot36;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
public class HFFax extends BaseMode {
|
||||
private final ExponentialMovingAverage lowPassFilter;
|
||||
private final int smallPictureMaxSamples;
|
||||
private final int mediumPictureMaxSamples;
|
||||
private final String name;
|
||||
|
||||
private final int sr;
|
||||
|
||||
private final float[] cumulated;
|
||||
private int horizontalShift = 0;
|
||||
|
||||
HFFax(String name, int sampleRate) {
|
||||
this.name = name;
|
||||
smallPictureMaxSamples = (int) Math.round(0.125 * sampleRate);
|
||||
mediumPictureMaxSamples = (int) Math.round(0.175 * sampleRate);
|
||||
lowPassFilter = new ExponentialMovingAverage();
|
||||
this.sr = sampleRate;
|
||||
cumulated = new float[getWidth()];
|
||||
}
|
||||
|
||||
private float freqToLevel(float frequency, float offset) {
|
||||
|
@ -55,6 +57,11 @@ public class HFFax extends BaseMode {
|
|||
return sr / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEstimatedHorizontalShift() {
|
||||
return horizontalShift;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
}
|
||||
|
@ -63,22 +70,38 @@ public class HFFax extends BaseMode {
|
|||
public boolean decodeScanLine(PixelBuffer pixelBuffer, float[] scratchBuffer, float[] scanLineBuffer, int scopeBufferWidth, int syncPulseIndex, int scanLineSamples, float frequencyOffset) {
|
||||
if (syncPulseIndex < 0 || syncPulseIndex + scanLineSamples > scanLineBuffer.length)
|
||||
return false;
|
||||
int horizontalPixels = scopeBufferWidth;
|
||||
if (scanLineSamples < smallPictureMaxSamples)
|
||||
horizontalPixels /= 2;
|
||||
if (scanLineSamples < mediumPictureMaxSamples)
|
||||
horizontalPixels /= 2;
|
||||
int horizontalPixels = getWidth();
|
||||
lowPassFilter.cutoff(horizontalPixels, 2 * scanLineSamples, 2);
|
||||
lowPassFilter.reset();
|
||||
for (int i = 0; i < scanLineSamples; ++i)
|
||||
scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[syncPulseIndex + i]);
|
||||
scratchBuffer[i] = lowPassFilter.avg(scanLineBuffer[i]);
|
||||
lowPassFilter.reset();
|
||||
for (int i = scanLineSamples - 1; i >= 0; --i)
|
||||
scratchBuffer[i] = freqToLevel(lowPassFilter.avg(scratchBuffer[i]), frequencyOffset);
|
||||
for (int i = 0; i < horizontalPixels; ++i) {
|
||||
int position = (i * scanLineSamples) / horizontalPixels;
|
||||
pixelBuffer.pixels[i] = ColorConverter.GRAY(scratchBuffer[position]);
|
||||
int color = ColorConverter.GRAY(scratchBuffer[position]);
|
||||
pixelBuffer.pixels[i] = color;
|
||||
|
||||
cumulated[i] *= 0.99f; //decay old data
|
||||
cumulated[i] += Color.luminance(color);
|
||||
}
|
||||
|
||||
//try to detect "sync": thick white margin
|
||||
int bestIndex = 0;
|
||||
float bestValue = 0;
|
||||
for (int x = 0; x < getWidth(); ++x)
|
||||
{
|
||||
float val = cumulated[x];
|
||||
if (val > bestValue)
|
||||
{
|
||||
bestIndex = x;
|
||||
bestValue = val;
|
||||
}
|
||||
}
|
||||
|
||||
horizontalShift = bestIndex;
|
||||
|
||||
pixelBuffer.width = horizontalPixels;
|
||||
pixelBuffer.height = 1;
|
||||
return true;
|
||||
|
|
|
@ -15,6 +15,7 @@ import android.content.SharedPreferences;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioRecord;
|
||||
|
@ -846,6 +847,19 @@ public class MainActivity extends AppCompatActivity {
|
|||
Bitmap bmp = Bitmap.createBitmap(scopeBuffer.pixels, offset, stride, width, height, Bitmap.Config.ARGB_8888);
|
||||
if (currentMode == null || !currentMode.equals("HF Fax")) {
|
||||
bmp = Bitmap.createScaledBitmap(bmp, width / 3, height / 3, true);
|
||||
} else {
|
||||
Mode mode = decoder.currentMode;
|
||||
int shift = mode.getEstimatedHorizontalShift();
|
||||
if (shift > 0) {
|
||||
Bitmap part1 = Bitmap.createBitmap(bmp, 0, 0, shift, bmp.getHeight());
|
||||
Bitmap part2 = Bitmap.createBitmap(bmp, shift, 0, mode.getWidth() - shift, bmp.getHeight());
|
||||
|
||||
Bitmap bmpMutable = Bitmap.createBitmap(mode.getWidth(), bmp.getHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new android.graphics.Canvas(bmpMutable);
|
||||
canvas.drawBitmap(part2, 0, 1, null);
|
||||
canvas.drawBitmap(part1, mode.getWidth() - shift, 0, null);
|
||||
bmp = bmpMutable;
|
||||
}
|
||||
}
|
||||
storeBitmap(bmp);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ public interface Mode {
|
|||
*/
|
||||
int getScanLineSamples();
|
||||
|
||||
/**
|
||||
* @return number of pixels of horizontal shift based on recent data, nonzero for HF Fax
|
||||
*/
|
||||
int getEstimatedHorizontalShift();
|
||||
|
||||
/**
|
||||
* Reset internal state.
|
||||
*/
|
||||
|
|
Ładowanie…
Reference in New Issue