Detecting white margin in HF Fax mode and correcting image shift when saving

pull/38/head
Marek Ossowski 2025-08-16 22:09:29 +02:00
rodzic 9558080ff8
commit 638484ae78
4 zmienionych plików z 57 dodań i 11 usunięć

Wyświetl plik

@ -1,4 +1,8 @@
package xdsopl.robot36;
public abstract class BaseMode implements Mode {
@Override
public int getEstimatedHorizontalShift() {
return 0;
}
}

Wyświetl plik

@ -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;

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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.
*/