Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static cropping #1610

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
d6054d2
Add static cropping
Alextopher Oct 6, 2024
7d0ba3c
add newline after license
Alextopher Oct 6, 2024
ffc5645
prettier
Alextopher Oct 6, 2024
ec68d5b
fixed issue with drawing tags without offset
GGreenix Nov 29, 2024
e49acf7
spotlessed
GGreenix Nov 30, 2024
bab4fb1
Update photon-server/src/main/resources/web/index.html
GGreenix Nov 30, 2024
8e8c17b
Update index.html
crschardt Dec 6, 2024
b5cde88
Update index.html
crschardt Dec 6, 2024
4e10fae
Update index.html
crschardt Dec 6, 2024
736900e
removing index.html, which shouldn't be tracked
crschardt Dec 9, 2024
827dfc4
Reverted contents of index.html
crschardt Dec 9, 2024
dedd6b2
Merge branch 'master' into static_cropping
crschardt Dec 9, 2024
036be1a
Typo in license
crschardt Dec 9, 2024
d15f1f3
cropped frame released after tag detection
GGreenix Dec 9, 2024
3b2fa8d
uncropping pipe and more
GGreenix Dec 10, 2024
d33d67f
forgot to delete old offset method
GGreenix Dec 10, 2024
28444ca
fixed set params
GGreenix Dec 11, 2024
c8e470c
Update index.html
GGreenix Dec 12, 2024
ad772d1
homography seems like it is not changing and offset works correctly
GGreenix Dec 13, 2024
a67059e
Uncropping for aruco, and offseting homography
GGreenix Dec 15, 2024
381f4ad
colored shapes uncropping pipeline
GGreenix Dec 15, 2024
1817aa4
Unit test available at test...photonvision\vision\pipeline\UncropApri…
GGreenix Dec 16, 2024
ae8a3cd
added uncropping for object detection and tightened the deltas for un…
GGreenix Dec 17, 2024
ed1b0b3
Merge branch 'master' into static_cropping
GGreenix Dec 17, 2024
f2ecf12
tests passed for skew, yaw, pitch and area, and UI fixed for bars and…
GGreenix Dec 17, 2024
967e8f2
Any implemented pipeline but reflective has cropping mechanism, and t…
GGreenix Dec 19, 2024
75336b8
Run lint
mcm001 Dec 19, 2024
f7313e9
Revert package-lock
mcm001 Dec 19, 2024
934e389
reflective is filtered from having cropping pipe and colored shape is…
GGreenix Dec 21, 2024
ab0fd06
Merge branch 'main' into static_cropping
GGreenix Dec 21, 2024
6d8981a
Update photon-core/src/main/java/org/photonvision/vision/pipeline/Apr…
GGreenix Dec 22, 2024
2b191fe
crop pipe dimensions can now not be bellow 16
GGreenix Dec 22, 2024
657b649
now fixed setParams
GGreenix Dec 22, 2024
dbf82be
not copying CVMat in pipeline and deleted fullyCover check
GGreenix Dec 24, 2024
f82913b
Update UncropApriltagsPipe.java
GGreenix Dec 24, 2024
1db370a
Update CropPipe.java
GGreenix Dec 24, 2024
b221b24
Reverted content of file.
GGreenix Dec 26, 2024
1186b3a
spotlessed
GGreenix Dec 26, 2024
3a0407d
Merge branch 'main' into static_cropping
GGreenix Dec 26, 2024
bda1378
Solved failed commit tasks
GGreenix Dec 26, 2024
80a5ab4
Update UncropApriltagTest.java
GGreenix Dec 26, 2024
527384a
formated
GGreenix Dec 26, 2024
9198e08
formated again
GGreenix Dec 26, 2024
9e23320
aurco color released and method moved
GGreenix Dec 26, 2024
b56f6c0
spotlessed
GGreenix Dec 26, 2024
b059573
moved cropping values to CVPipelineSettings for chaching when switchi…
GGreenix Dec 26, 2024
b819899
Update ArucoPipeline.java
GGreenix Dec 27, 2024
1d5d576
Update ArucoPipeline.java
GGreenix Dec 27, 2024
ba3cf58
Update ArucoPipeline.java
GGreenix Dec 27, 2024
9f513c2
Merge branch 'main' into static_cropping
GGreenix Dec 28, 2024
647dcc6
Implementation of recomputation of homography with offsetted corners
GGreenix Dec 30, 2024
503846f
Revert "Implementation of recomputation of homography with offsetted …
GGreenix Dec 30, 2024
c8d280f
Update UncropApriltagsPipe.java
GGreenix Dec 30, 2024
40e37f6
Update UncropApriltagsPipe.java
GGreenix Dec 30, 2024
fdae7eb
Merge branch 'main' into static_cropping
GGreenix Dec 30, 2024
0562e9e
testing build without crop
GGreenix Dec 30, 2024
848fab2
Merge branch 'static_cropping' of https://github.com/GGreenix/photonv…
GGreenix Dec 30, 2024
0362220
revert commit
GGreenix Dec 30, 2024
6a43579
homography recalculating working on tests
GGreenix Jan 1, 2025
5bbc6e1
Merge branch 'main' into static_cropping
GGreenix Jan 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions photon-client/src/components/dashboard/ConfigOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ThresholdTab from "@/components/dashboard/tabs/ThresholdTab.vue";
import ContoursTab from "@/components/dashboard/tabs/ContoursTab.vue";
import AprilTagTab from "@/components/dashboard/tabs/AprilTagTab.vue";
import ArucoTab from "@/components/dashboard/tabs/ArucoTab.vue";
import CropTab from "./tabs/CropTab.vue";
import ObjectDetectionTab from "@/components/dashboard/tabs/ObjectDetectionTab.vue";
import OutputTab from "@/components/dashboard/tabs/OutputTab.vue";
import TargetsTab from "@/components/dashboard/tabs/TargetsTab.vue";
Expand All @@ -25,6 +26,10 @@ const allTabs = Object.freeze({
tabName: "Input",
component: InputTab
},
cropTab: {
tabName: "Crop",
component: CropTab
},
thresholdTab: {
tabName: "Threshold",
component: ThresholdTab
Expand Down Expand Up @@ -76,6 +81,7 @@ const getTabGroups = (): ConfigOption[][] => {
return [
[
allTabs.inputTab,
allTabs.cropTab,
allTabs.thresholdTab,
allTabs.contoursTab,
allTabs.apriltagTab,
Expand All @@ -87,7 +93,7 @@ const getTabGroups = (): ConfigOption[][] => {
];
} else if (lgAndDown) {
return [
[allTabs.inputTab],
[allTabs.inputTab, allTabs.cropTab],
[
allTabs.thresholdTab,
allTabs.contoursTab,
Expand All @@ -100,7 +106,7 @@ const getTabGroups = (): ConfigOption[][] => {
];
} else if (xl) {
return [
[allTabs.inputTab],
[allTabs.inputTab, allTabs.cropTab],
[allTabs.thresholdTab],
[allTabs.contoursTab, allTabs.apriltagTab, allTabs.arucoTab, allTabs.objectDetectionTab, allTabs.outputTab],
[allTabs.targetsTab, allTabs.pnpTab, allTabs.map3dTab]
Expand All @@ -118,6 +124,7 @@ const tabGroups = computed<ConfigOption[][]>(() => {
const isAruco = useCameraSettingsStore().currentWebsocketPipelineType === WebsocketPipelineType.Aruco;
const isObjectDetection =
useCameraSettingsStore().currentWebsocketPipelineType === WebsocketPipelineType.ObjectDetection;
const isReflective = useCameraSettingsStore().currentWebsocketPipelineType === WebsocketPipelineType.Reflective;

return getTabGroups()
.map((tabGroup) =>
Expand All @@ -128,8 +135,9 @@ const tabGroups = computed<ConfigOption[][]>(() => {
!((isAprilTag || isAruco || isObjectDetection) && tabConfig.tabName === "Threshold") && //Filter out threshold tab if we're doing AprilTags
!((isAprilTag || isAruco || isObjectDetection) && tabConfig.tabName === "Contours") && //Filter out contours if we're doing AprilTags
!(!isAprilTag && tabConfig.tabName === "AprilTag") && //Filter out apriltag unless we actually are doing AprilTags
!(!isAruco && tabConfig.tabName === "Aruco") &&
!(!isObjectDetection && tabConfig.tabName === "Object Detection") //Filter out aruco unless we actually are doing Aruco
!(!isAruco && tabConfig.tabName === "Aruco") && //Filter out aruco unless we actually are doing Aruco
!(!isObjectDetection && tabConfig.tabName === "Object Detection") &&
!(isReflective && tabConfig.tabName === "Crop")
)
)
.filter((it) => it.length); // Remove empty tab groups
Expand Down
60 changes: 60 additions & 0 deletions photon-client/src/components/dashboard/tabs/CropTab.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup lang="ts">
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { type ActivePipelineSettings } from "@/types/PipelineTypes";
import PvSlider from "@/components/common/pv-slider.vue";
import { computed, getCurrentInstance } from "vue";
import { useStateStore } from "@/stores/StateStore";
const currentPipelineSettings = computed<ActivePipelineSettings>(
() => useCameraSettingsStore().currentPipelineSettings as ActivePipelineSettings
);
const frame_width = computed(() => useCameraSettingsStore().currentVideoFormat.resolution.width);
const frame_height = computed(() => useCameraSettingsStore().currentVideoFormat.resolution.height);
const interactiveCols = computed(() =>
(getCurrentInstance()?.proxy.$vuetify.breakpoint.mdAndDown || false) &&
(!useStateStore().sidebarFolded || useCameraSettingsStore().isDriverMode)
? 9
: 8
);
</script>
<template>
<div>
<v-card-subtitle class="white--text">Static Crop</v-card-subtitle>
<pv-slider
v-model="currentPipelineSettings.static_x"
class="pt-2"
:slider-cols="interactiveCols"
label="X"
tooltip="The X coordinate of the top left corner of the statically cropped area"
:min="0"
:max="frame_width"
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ static_x: value }, false)"
/>
<pv-slider
v-model="currentPipelineSettings.static_y"
:slider-cols="interactiveCols"
label="Y"
tooltip="The Y coordinate of the top left corner of the statically cropped area"
:min="0"
:max="frame_height"
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ static_y: value }, false)"
/>
<pv-slider
v-model="currentPipelineSettings.static_width"
:slider-cols="interactiveCols"
label="Width"
tooltip="The width of the statically cropped area"
:min="16"
:max="frame_width"
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ static_width: value }, false)"
/>
<pv-slider
v-model="currentPipelineSettings.static_height"
:slider-cols="interactiveCols"
label="Height"
tooltip="The height of the statically cropped area"
:min="16"
:max="frame_height"
@input="(value) => useCameraSettingsStore().changeCurrentPipelineSetting({ static_height: value }, false)"
/>
</div>
</template>
8 changes: 7 additions & 1 deletion photon-client/src/components/dashboard/tabs/InputTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ const cameraResolutions = computed(() =>
);
const handleResolutionChange = (value: number) => {
useCameraSettingsStore().changeCurrentPipelineSetting({ cameraVideoModeIndex: value }, false);

const currResolutions = useCameraSettingsStore().currentVideoFormat.resolution;
useCameraSettingsStore().changeCurrentPipelineSetting({
static_x: 0,
static_y: 0,
static_height: currResolutions.height,
static_width: currResolutions.width
});
useCameraSettingsStore().changeCurrentPipelineSetting({ streamingFrameDivisor: getNumberOfSkippedDivisors() }, false);
useCameraSettingsStore().currentPipelineSettings.streamingFrameDivisor = 0;

Expand Down
10 changes: 9 additions & 1 deletion photon-client/src/types/PipelineTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ export interface PipelineSettings {

cameraAutoWhiteBalance: boolean;
cameraWhiteBalanceTemp: number;
static_x: number;
static_y: number;
static_width: number;
static_height: number;
}
export type ConfigurablePipelineSettings = Partial<
Omit<
Expand Down Expand Up @@ -143,7 +147,11 @@ export const DefaultPipelineSettings: Omit<
cameraAutoWhiteBalance: false,
cameraWhiteBalanceTemp: 4000,
cameraMinExposureRaw: 1,
cameraMaxExposureRaw: 2
cameraMaxExposureRaw: 2,
static_x: 0,
static_y: 0,
static_width: 0,
static_height: 0
};

export interface ReflectivePipelineSettings extends PipelineSettings {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.photonvision.common.util;

import org.opencv.core.Mat;
import org.opencv.core.Rect;

public class CroppingUtils {
/**
* Returns true if the given rectangle fully covers some given image.
*
* @param rect The rectangle to check.
* @param mat The image to check.
* @return boolean
*/
public static boolean fullyCovers(Rect rect, Mat mat) {
return rect.x <= 0 && rect.y <= 0 && rect.width >= mat.width() && rect.height >= mat.height();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.photonvision.vision.pipe.impl;

import edu.wpi.first.math.MathUtil;
import org.opencv.core.Rect;
import org.photonvision.vision.opencv.CVMat;
import org.photonvision.vision.pipe.CVPipe;

public class CropPipe extends CVPipe<CVMat, CVMat, Rect> {
public CropPipe(int width, int height) {
this.params = new Rect(0, 0, width, height);
}

@Override
protected CVMat process(CVMat in) {
int x = MathUtil.clamp(params.x, 0, in.getMat().width());
int y = MathUtil.clamp(params.y, 0, in.getMat().height());
int width = MathUtil.clamp(params.width, 0, in.getMat().width() - x);
int height = MathUtil.clamp(params.height, 0, in.getMat().height() - y);

return new CVMat(in.getMat().submat(y, y + height, x, x + width));
}

@Override
public void setParams(Rect params) {
params.height = Math.max(16, params.height);
params.width = Math.max(16, params.width);
mcm001 marked this conversation as resolved.
Show resolved Hide resolved

super.setParams(params);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (C) Photon Vision.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.photonvision.vision.pipe.impl;

import edu.wpi.first.math.MathUtil;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgproc.Imgproc;
import org.photonvision.common.util.CroppingUtils;
import org.photonvision.vision.pipe.MutatingPipe;

public class DrawRectanglePipe
extends MutatingPipe<Mat, DrawRectanglePipe.DrawRectanglePipeParams> {
Scalar color;

public DrawRectanglePipe(Scalar color) {
super();
this.params = new DrawRectanglePipeParams();
this.color = color;
}

@Override
protected Void process(Mat in) {
// Draw nothing if the rectangle fully covers the image
if (CroppingUtils.fullyCovers(params.rect, in)) {
return null;
}

int x = MathUtil.clamp(params.rect.x, 0, in.width());
int y = MathUtil.clamp(params.rect.y, 0, in.height());
int width = MathUtil.clamp(params.rect.width, 0, in.width() - x);
int height = MathUtil.clamp(params.rect.height, 0, in.height() - y);
Rect rect = new Rect(x, y, width, height);

Imgproc.rectangle(in, rect, this.color, params.thickness);
return null;
}

public static class DrawRectanglePipeParams {
public Rect rect = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
public int thickness = 2;

public DrawRectanglePipeParams() {}

public DrawRectanglePipeParams(Rect rect) {
this.rect = rect;
}

public DrawRectanglePipeParams(int x, int y, int width, int height) {
this(new Rect(x, y, width, height));
}
}
}
Loading
Loading