Agrarsense
TreeHeightsFromImageComponent.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
7#include <string.h>
8
9UTreeHeightsFromImageComponent::UTreeHeightsFromImageComponent()
10{
11 PrimaryComponentTick.bCanEverTick = false;
12}
13
14void UTreeHeightsFromImageComponent::BeginPlay()
15{
16 Super::BeginPlay();
17}
18
19void UTreeHeightsFromImageComponent::CacheTexture()
20{
21#if WITH_EDITOR
22 FString TexturePath = TEXT("/Game/Agrarsense/Maps/Vindeln/CHM_Vindeln.CHM_Vindeln");
23 treeMapImage = Cast<UTexture2D>(StaticLoadObject(UTexture2D::StaticClass(), nullptr, *TexturePath));
24 if (treeMapImage)
25 {
26 FTexture2DMipMap& Mip = treeMapImage->GetPlatformData()->Mips[0];
27 void* Data = Mip.BulkData.Lock(LOCK_READ_ONLY);
28 int32 Size = Mip.BulkData.GetBulkDataSize();
29 Pixels.Empty();
30 Pixels.AddUninitialized(Size);
31
32 std::memcpy(Pixels.GetData(), Data, Size);
33
34 Mip.BulkData.Unlock();
35
36 UE_LOG(LogTemp, Warning, TEXT("Tree image cached.."));
37 UE_LOG(LogTemp, Warning, TEXT("Pixels data len %i"), Pixels.Num());
38
39 Width = treeMapImage->GetSizeX();
40 Height = treeMapImage->GetSizeY();
41
42 UE_LOG(LogTemp, Warning, TEXT("Source image resolution: %i x %i"), Width, Height);
43 }
44#endif
45}
46
47float UTreeHeightsFromImageComponent::EuclideanDistance(const FColor& Color1, const FColor& Color2)
48{
49 float R1 = Color1.R;
50 float G1 = Color1.G;
51 float B1 = Color1.B;
52 float R2 = Color2.R;
53 float G2 = Color2.G;
54 float B2 = Color2.B;
55 return FMath::Sqrt(FMath::Square(R2 - R1) + FMath::Square(G2 - G1) + FMath::Square(B2 - B1));
56}
57
58FColor UTreeHeightsFromImageComponent::FindClosestColor(const FColor& TargetColor, const TMap<int32, FColor>& ColorMap)
59{
60 float MinDistance = FLT_MAX;
61 FColor ClosestColor;
62
63 for (const auto& Pair : ColorMap)
64 {
65 float Distance = EuclideanDistance(TargetColor, Pair.Value);
66 if (Distance < MinDistance)
67 {
68 MinDistance = Distance;
69 ClosestColor = Pair.Value;
70 }
71 }
72
73 return ClosestColor;
74}
75
76int UTreeHeightsFromImageComponent::GetColorFromPixel(FVector point)
77{
78 //if (!treeMapImage)
79 // return 0;// FColor::Black;
80
81
82 if (Pixels.IsEmpty())
83 {
84 UE_LOG(LogTemp, Warning, TEXT("Returning from Pixels are empty!"));
85 return 0;
86 }
87
88
89
90 //UE_LOG(LogTemp, Warning, TEXT("Coordinate: %f"), point);
91
92 point.X /= 122.9033;
93 point.Y /= 122.9033;
94
95 if (point.X <= 0 || point.Y <= 0)
96 {
97 UE_LOG(LogTemp, Warning, TEXT("Returning from point less than 0"));
98 return 0;// FColor::Black;
99 }
100
101 // Lock the texture to allow access to its data
102 //FTexture2DMipMap& Mip = treeMapImage->GetPlatformData()->Mips[0];
103
104 //if (Mip.BulkData.IsLocked())
105 // return;// FColor::Black;
106
107 //if (Mip.BulkData.IsLocked())
108 // Mip.BulkData.Unlock();
109
110 //void* Data = Mip.BulkData.Lock(LOCK_READ_ONLY);
111
112 //if (!Data)
113 //{
114 // Mip.BulkData.Unlock();
115 // return FColor::Black;
116 //}
117
118
119 // Get image resolution
120 /*Width = treeMapImage->GetSizeX();
121 Height = treeMapImage->GetSizeY();*/
122
123 if (point.X > Width || point.Y > Height)
124 {
125 //Mip.BulkData.Unlock();
126 UE_LOG(LogTemp, Warning, TEXT("Returning from point over the resolution"));
127 return 0;
128 }
129
130 // If width and height not good, return black
131 if (Width <= 0 || Height <= 0)
132 {
133 //if (Mip.BulkData.IsLocked())
134 //Mip.BulkData.Unlock();
135 UE_LOG(LogTemp, Warning, TEXT("Returning from width <= 0"));
136 return 0;// FColor::Black;
137 }
138
139
140 //uint8* Pixels = static_cast<uint8*>(Data);
141
142 int32 Index = ((int)point.Y * Width + (int)point.X) * 4; // 4 bytes per pixel (RGBA)
143
144 if (Index + 3 <= Pixels.Num())
145 {
146 uint8 R = Pixels[Index];
147 uint8 G = Pixels[Index + 1];
148 uint8 B = Pixels[Index + 2];
149 //uint8 A = Pixels[Index + 3];
150
151 FColor pixelColor = FColor(B, G, R);
152
153 FColor closestColor = FindClosestColor(pixelColor, colorHeight);
154
155 for (const auto& Pair : colorHeight)
156 {
157 if (Pair.Value == closestColor)
158 {
159 UE_LOG(LogTemp, Warning, TEXT("This tree is : %i m"), Pair.Key);
160 return Pair.Key;
161 }
162 }
163 }
164 else {
165 UE_LOG(LogTemp, Warning, TEXT("Index out of range"));
166 }
167
168
169
170 // Unlock the texture
171 //Mip.BulkData.Unlock();
172
173 //return pixelColor;
174 return 0;
175}
176
177#if WITH_EDITOR
178void UTreeHeightsFromImageComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
179{
180 Super::PostEditChangeProperty(PropertyChangedEvent);
181
182 // Check if the custom button trigger has been toggled
183 if (PropertyChangedEvent.Property != nullptr && PropertyChangedEvent.Property->GetName() == "GenerateTrigger")
184 {
185 if (GenerateTrigger)
186 {
187 CacheTexture();
188 GenerateTrigger = false;
189 }
190 }
191}
192#endif