Skip to content

Commit

Permalink
[wpiutil,cscore,apriltag] Fix RawFrame (#6098)
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJohnson authored Dec 27, 2023
1 parent 8aeee03 commit 5659038
Show file tree
Hide file tree
Showing 18 changed files with 528 additions and 308 deletions.
8 changes: 6 additions & 2 deletions apriltag/src/main/java/edu/wpi/first/apriltag/AprilTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public String toString() {
* @return A RawFrame containing the AprilTag image
*/
public static RawFrame generate16h5AprilTagImage(int id) {
return AprilTagJNI.generate16h5AprilTagImage(id);
RawFrame frame = new RawFrame();
AprilTagJNI.generate16h5AprilTagImage(frame, frame.getNativeObj(), id);
return frame;
}

/**
Expand All @@ -64,6 +66,8 @@ public static RawFrame generate16h5AprilTagImage(int id) {
* @return A RawFrame containing the AprilTag image
*/
public static RawFrame generate36h11AprilTagImage(int id) {
return AprilTagJNI.generate36h11AprilTagImage(id);
RawFrame frame = new RawFrame();
AprilTagJNI.generate36h11AprilTagImage(frame, frame.getNativeObj(), id);
return frame;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public static native Transform3d estimatePose(
double cx,
double cy);

public static native RawFrame generate16h5AprilTagImage(int id);
public static native void generate16h5AprilTagImage(RawFrame frameObj, long frame, int id);

public static native RawFrame generate36h11AprilTagImage(int id);
public static native void generate36h11AprilTagImage(RawFrame frameObj, long frame, int id);
}
51 changes: 23 additions & 28 deletions apriltag/src/main/native/cpp/AprilTag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "frc/apriltag/AprilTag.h"

#include <cstring>

#include <wpi/json.h>

#ifdef _WIN32
Expand All @@ -20,40 +22,33 @@

using namespace frc;

wpi::RawFrame AprilTag::Generate36h11AprilTagImage(int id) {
apriltag_family_t* tagFamily = tag36h11_create();
image_u8_t* image = apriltag_to_image(tagFamily, id);
wpi::RawFrame markerFrame{};
size_t totalDataSize = image->height * image->stride * sizeof(char);
markerFrame.data = static_cast<char*>(
std::calloc(image->height * image->stride, sizeof(char)));
std::memcpy(markerFrame.data, image->buf, totalDataSize);
markerFrame.dataLength = image->width;
markerFrame.height = image->height;
markerFrame.pixelFormat = WPI_PIXFMT_GRAY;
markerFrame.width = image->stride;
markerFrame.totalData = totalDataSize;
static bool FamilyToImage(wpi::RawFrame* frame, apriltag_family_t* family,
int id) {
image_u8_t* image = apriltag_to_image(family, id);
size_t totalDataSize = image->height * image->stride;
bool rv = frame->Reserve(totalDataSize);
std::memcpy(frame->data, image->buf, totalDataSize);
frame->size = totalDataSize;
frame->width = image->width;
frame->height = image->height;
frame->stride = image->stride;
frame->pixelFormat = WPI_PIXFMT_GRAY;
image_u8_destroy(image);
return rv;
}

bool AprilTag::Generate36h11AprilTagImage(wpi::RawFrame* frame, int id) {
apriltag_family_t* tagFamily = tag36h11_create();
bool rv = FamilyToImage(frame, tagFamily, id);
tag36h11_destroy(tagFamily);
return markerFrame;
return rv;
}

wpi::RawFrame AprilTag::Generate16h5AprilTagImage(int id) {
bool AprilTag::Generate16h5AprilTagImage(wpi::RawFrame* frame, int id) {
apriltag_family_t* tagFamily = tag16h5_create();
image_u8_t* image = apriltag_to_image(tagFamily, id);
wpi::RawFrame markerFrame{};
size_t totalDataSize = image->height * image->stride * sizeof(char);
markerFrame.data = static_cast<char*>(
std::calloc(image->height * image->stride, sizeof(char)));
std::memcpy(markerFrame.data, image->buf, totalDataSize);
markerFrame.dataLength = image->width;
markerFrame.height = image->height;
markerFrame.pixelFormat = WPI_PIXFMT_GRAY;
markerFrame.width = image->stride;
markerFrame.totalData = totalDataSize;
image_u8_destroy(image);
bool rv = FamilyToImage(frame, tagFamily, id);
tag16h5_destroy(tagFamily);
return markerFrame;
return rv;
}

void frc::to_json(wpi::json& json, const AprilTag& apriltag) {
Expand Down
47 changes: 24 additions & 23 deletions apriltag/src/main/native/cpp/jni/AprilTagJNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

#include <jni.h>

#include <cstdio>
#include <cstring>

#define WPI_RAWFRAME_JNI
#include <wpi/RawFrame.h>
#include <wpi/jni_util.h>

Expand Down Expand Up @@ -319,21 +322,6 @@ static jobject MakeJObject(JNIEnv* env, const AprilTagPoseEstimate& est) {
static_cast<jdouble>(est.error2));
}

static jobject MakeJObject(JNIEnv* env, const wpi::RawFrame& frame) {
static jmethodID constructor = env->GetMethodID(rawFrameCls, "<init>", "()V");

static jmethodID setData =
env->GetMethodID(rawFrameCls, "setData", "(Ljava/nio/ByteBuffer;JIIII)V");

jobject retVal = env->NewObject(rawFrameCls, constructor);
env->CallVoidMethod(
retVal, setData, env->NewDirectByteBuffer(frame.data, frame.totalData),
static_cast<jlong>(reinterpret_cast<intptr_t>(frame.data)),
static_cast<jint>(frame.dataLength), static_cast<jint>(frame.width),
static_cast<jint>(frame.height), static_cast<jint>(frame.pixelFormat));
return retVal;
}

extern "C" {

/*
Expand Down Expand Up @@ -609,25 +597,38 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePose
/*
* Class: edu_wpi_first_apriltag_jni_AprilTagJNI
* Method: generate16h5AprilTagImage
* Signature: (I)Ljava/lang/Object;
* Signature: (Ljava/lang/Object;JI)V
*/
JNIEXPORT jobject JNICALL
JNIEXPORT void JNICALL
Java_edu_wpi_first_apriltag_jni_AprilTagJNI_generate16h5AprilTagImage
(JNIEnv* env, jclass, jint id)
(JNIEnv* env, jclass, jobject frameObj, jlong framePtr, jint id)
{
return MakeJObject(env, AprilTag::Generate16h5AprilTagImage(id));
auto* frame = reinterpret_cast<wpi::RawFrame*>(framePtr);
if (!frame) {
nullPointerEx.Throw(env, "frame is null");
return;
}
bool newData = AprilTag::Generate16h5AprilTagImage(frame, id);
wpi::SetFrameData(env, rawFrameCls, frameObj, *frame, newData);
}

/*
* Class: edu_wpi_first_apriltag_jni_AprilTagJNI
* Method: generate36h11AprilTagImage
* Signature: (I)Ljava/lang/Object;
* Signature: (Ljava/lang/Object;JI)V
*/
JNIEXPORT jobject JNICALL
JNIEXPORT void JNICALL
Java_edu_wpi_first_apriltag_jni_AprilTagJNI_generate36h11AprilTagImage
(JNIEnv* env, jclass, jint id)
(JNIEnv* env, jclass, jobject frameObj, jlong framePtr, jint id)
{
return MakeJObject(env, AprilTag::Generate36h11AprilTagImage(id));
auto* frame = reinterpret_cast<wpi::RawFrame*>(framePtr);
if (!frame) {
nullPointerEx.Throw(env, "frame is null");
return;
}
// function might reallocate
bool newData = AprilTag::Generate36h11AprilTagImage(frame, id);
wpi::SetFrameData(env, rawFrameCls, frameObj, *frame, newData);
}

} // extern "C"
4 changes: 2 additions & 2 deletions apriltag/src/main/native/include/frc/apriltag/AprilTag.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct WPILIB_DLLEXPORT AprilTag {
*/
bool operator==(const AprilTag&) const = default;

static wpi::RawFrame Generate36h11AprilTagImage(int id);
static wpi::RawFrame Generate16h5AprilTagImage(int id);
static bool Generate36h11AprilTagImage(wpi::RawFrame* frame, int id);
static bool Generate16h5AprilTagImage(wpi::RawFrame* frame, int id);
};

WPILIB_DLLEXPORT
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package edu.wpi.first.apriltag;

import static org.junit.jupiter.api.Assertions.assertEquals;

import edu.wpi.first.util.PixelFormat;
import org.junit.jupiter.api.Test;

class AprilTagGenerationTest {
@Test
void test36h11() {
var frame = AprilTag.generate36h11AprilTagImage(1);
assertEquals(PixelFormat.kGray, frame.getPixelFormat());
assertEquals(10, frame.getWidth());
assertEquals(10, frame.getHeight());
int stride = frame.getStride();
assertEquals(stride * 10, frame.getSize());
// check the diagonal values
var data = frame.getData();
assertEquals(-1, data.get(stride * 0 + 0)); // outer border is white
assertEquals(0, data.get(stride * 1 + 1)); // inner border is black
assertEquals(-1, data.get(stride * 2 + 2));
assertEquals(-1, data.get(stride * 3 + 3));
assertEquals(-1, data.get(stride * 4 + 4));
assertEquals(0, data.get(stride * 5 + 5));
assertEquals(0, data.get(stride * 6 + 6));
assertEquals(-1, data.get(stride * 7 + 7));
assertEquals(0, data.get(stride * 8 + 8)); // inner border
assertEquals(-1, data.get(stride * 9 + 9)); // outer border
}
}
63 changes: 9 additions & 54 deletions cscore/src/main/java/edu/wpi/first/cscore/CameraServerJNI.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,13 @@ public static native boolean setSourceVideoMode(
//
// Image Source Functions
//
public static native void putRawSourceFrame(int source, long frame);

public static native void putRawSourceFrameBB(
int source, ByteBuffer data, int width, int height, int pixelFormat, int totalData);

public static native void putRawSourceFrame(
int source, long data, int width, int height, int pixelFormat, int totalData);

public static void putRawSourceFrame(int source, RawFrame raw) {
putRawSourceFrame(
source,
raw.getDataPtr(),
raw.getWidth(),
raw.getHeight(),
raw.getPixelFormat(),
raw.getTotalData());
}
int source, ByteBuffer data, int size, int width, int height, int stride, int pixelFormat);

public static native void putRawSourceFrameData(
int source, long data, int size, int width, int height, int stride, int pixelFormat);

public static native void notifySourceError(int source, String msg);

Expand Down Expand Up @@ -263,47 +255,10 @@ public static native void setSourceEnumPropertyChoices(
//
public static native void setSinkDescription(int sink, String description);

private static native long grabRawSinkFrameImpl(
int sink,
RawFrame rawFrame,
long rawFramePtr,
ByteBuffer byteBuffer,
int width,
int height,
int pixelFormat);

private static native long grabRawSinkFrameTimeoutImpl(
int sink,
RawFrame rawFrame,
long rawFramePtr,
ByteBuffer byteBuffer,
int width,
int height,
int pixelFormat,
double timeout);

public static long grabSinkFrame(int sink, RawFrame rawFrame) {
return grabRawSinkFrameImpl(
sink,
rawFrame,
rawFrame.getFramePtr(),
rawFrame.getDataByteBuffer(),
rawFrame.getWidth(),
rawFrame.getHeight(),
rawFrame.getPixelFormat());
}
public static native long grabRawSinkFrame(int sink, RawFrame frame, long nativeObj);

public static long grabSinkFrameTimeout(int sink, RawFrame rawFrame, double timeout) {
return grabRawSinkFrameTimeoutImpl(
sink,
rawFrame,
rawFrame.getFramePtr(),
rawFrame.getDataByteBuffer(),
rawFrame.getWidth(),
rawFrame.getHeight(),
rawFrame.getPixelFormat(),
timeout);
}
public static native long grabRawSinkFrameTimeout(
int sink, RawFrame frame, long nativeObj, double timeout);

public static native String getSinkError(int sink);

Expand Down
10 changes: 5 additions & 5 deletions cscore/src/main/java/edu/wpi/first/cscore/raw/RawSink.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public RawSink(String name) {
* @return Frame time, or 0 on error (call getError() to obtain the error message); the frame time
* is in the same time base as wpi::Now(), and is in 1 us increments.
*/
protected long grabFrame(RawFrame frame) {
public long grabFrame(RawFrame frame) {
return grabFrame(frame, 0.225);
}

Expand All @@ -46,8 +46,8 @@ protected long grabFrame(RawFrame frame) {
* @return Frame time, or 0 on error (call getError() to obtain the error message); the frame time
* is in the same time base as wpi::Now(), and is in 1 us increments.
*/
protected long grabFrame(RawFrame frame, double timeout) {
return CameraServerJNI.grabSinkFrameTimeout(m_handle, frame, timeout);
public long grabFrame(RawFrame frame, double timeout) {
return CameraServerJNI.grabRawSinkFrameTimeout(m_handle, frame, frame.getNativeObj(), timeout);
}

/**
Expand All @@ -58,7 +58,7 @@ protected long grabFrame(RawFrame frame, double timeout) {
* @return Frame time, or 0 on error (call getError() to obtain the error message); the frame time
* is in the same time base as wpi::Now(), and is in 1 us increments.
*/
protected long grabFrameNoTimeout(RawFrame frame) {
return CameraServerJNI.grabSinkFrame(m_handle, frame);
public long grabFrameNoTimeout(RawFrame frame) {
return CameraServerJNI.grabRawSinkFrame(m_handle, frame, frame.getNativeObj());
}
}
Loading

0 comments on commit 5659038

Please sign in to comment.