teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

見直しキャンペーン中

2023/07/17 06:32

投稿

TN8001
TN8001

スコア10108

answer CHANGED
@@ -1,248 +1,248 @@
1
- 少なくともxamlを数行足すって程度では、できそうにもないですね。
2
- 何かライブラリ等はないかなとも思いましたが、見つけられませんでした。
3
-
4
- 案1 `OpenCV`的なもので画像を加工して重ねる。
5
- パフォーマンスもよさそうですし、コード量も少なそう。
6
- (私は魚眼にする方法は知りません^^;)
7
-
8
- 案2 球に適当に切り出した画像をマテリアルにマップし続ける。
9
- 雑に試してみましたが、特に重くはならず使えなくはないって感じでした。
10
- (自分でもよくわかっていない、雑なC#コードでよければ出せます)
11
-
12
- 参考コード追記
13
-
14
- ---
15
-
16
- 画像を加工パターン
17
- OpenCVとかわからないですが、GitHubでピュアC#のものを見つけたので試してみました。
18
- [AnthonyNystrom/GenXSource: Genetibase related source code](https://github.com/AnthonyNystrom/GenXSource) (どういったリポジトリなのか全くわかってません^^;)
19
-
20
- [IFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/IFilter.cs)
21
- [EffectFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/EffectFilter.cs)
22
- [FishEye.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/FishEye.cs)
23
- 上記3つをプロジェクトに追加(ライセンスが明示されていないので注意してください)
24
-
25
-
26
- ```xaml
27
- <Window
28
- x:Class="Questions228869.MainWindow"
29
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
30
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
31
- Title="Fisheye"
32
- MouseMove="Window_MouseMove"
33
- SizeToContent="WidthAndHeight">
34
- <Window.Resources>
35
- <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
36
- </Window.Resources>
37
-
38
- <Canvas Width="400" Height="300">
39
- <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
40
- <Image
41
- x:Name="zoomImage"
42
- Width="100"
43
- Height="100" />
44
-
45
- </Canvas>
46
- </Window>
47
- ```
48
-
49
- ```C#
50
- using System;
51
- using System.Windows;
52
- using System.Windows.Controls;
53
- using System.Windows.Input;
54
- using System.Windows.Media;
55
- using System.Windows.Media.Imaging;
56
- using Next2Friends.ImageWorks.EffectsFilters;
57
-
58
- namespace Questions228869
59
- {
60
- public partial class MainWindow : Window
61
- {
62
- private readonly RenderTargetBitmap inflateImage;
63
- private const double offset = 200;
64
- private int lastTimestamp;
65
-
66
- public MainWindow()
67
- {
68
- InitializeComponent();
69
-
70
- // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
71
- var image = (BitmapImage)Resources["earthImage"];
72
- var visual = new DrawingVisual();
73
- var dc = visual.RenderOpen();
74
- var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
75
- dc.DrawRectangle(Brushes.White, null, rect);
76
- dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
77
- dc.Close();
78
-
79
- inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
80
- inflateImage.Render(visual);
81
- }
82
-
83
- private void Window_MouseMove(object sender, MouseEventArgs e)
84
- {
85
- // GCが走り続けて引っかかるので適当に間引く
86
- if(Math.Abs(e.Timestamp - lastTimestamp) < 20) return;
87
- lastTimestamp = e.Timestamp;
88
-
89
- var p = e.GetPosition(sourceImage);
90
-
91
- zoomImage.SetValue(Canvas.LeftProperty, p.X - zoomImage.Width / 2);
92
- zoomImage.SetValue(Canvas.TopProperty, p.Y - zoomImage.Height / 2);
93
-
94
- var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
95
- var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
96
-
97
- var sourceX = ratioX * p.X;
98
- var sourceY = ratioY * p.Y;
99
-
100
- var w = ratioX * zoomImage.Width;
101
- var h = ratioY * zoomImage.Height;
102
- var x = sourceX - w / 2 + offset;
103
- var y = sourceY - h / 2 + offset;
104
- var rect = new Int32Rect((int)x, (int)y, (int)w, (int)h);
105
- try
106
- {
107
- var croppedBitmap = new CroppedBitmap(inflateImage, rect);
108
- zoomImage.Source = new FisheyeFilter(0.1f).ExecuteFilter(croppedBitmap);
109
- }
110
- catch { /* NOP CroppedBitmapが範囲外 */ }
111
- }
112
- }
113
- }
114
- ```
115
-
116
- 使用感
117
- * 画像を凸に加工しているので境目が見えなくて見た目はよい。
118
- * GCが走り続けて引っかかるので、適度に間引いたところまあまあ使えるかなと(高速化の余地はまだまだあるので、不満ならどうにかなる)
119
- * 原寸表示だと1ドットの線とかが荒れがち。
120
- ![イメージ説明](0d9b8293e9216706e81519b0a5011945.png)
121
- ---
122
-
123
-
124
- 球体に貼るパターン
125
- [WPF で 3D(その5) : リード開発メモ](http://freed411.doorblog.jp/archives/31528830.html)
126
- 基本的にはここの通り。
127
- `Primitive3D`と`Sphere3D`をプロジェクトに追加、`GetTextureCoordinate`を修正(元ネタはMicrosoftのサンプル 解凍時に使用許諾が出るので確認してください)
128
- xamlで書けることはできるだけ移したため、csは跡形ないです。
129
-
130
- ほか参考にしたサイト [WPF で地球を回してみるテスト - CX's Hatena Blog](http://cx20.hatenablog.com/entry/2014/02/11/215835)
131
-
132
- ```xaml
133
- <Window
134
- x:Class="Questions228869.MainWindow"
135
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
136
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
137
- xmlns:local="clr-namespace:Questions228869"
138
- Title="Sphere3D"
139
- MouseMove="Window_MouseMove"
140
- SizeToContent="WidthAndHeight">
141
- <Window.Resources>
142
- <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
143
- </Window.Resources>
144
-
145
- <Canvas Width="400" Height="300">
146
- <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
147
- <Viewport3D
148
- x:Name="viewport"
149
- Width="100"
150
- Height="100">
151
- <Viewport3D.Camera>
152
- <PerspectiveCamera
153
- LookDirection="0,0,-1"
154
- Position="0,0,3"
155
- UpDirection="0,1,0" />
156
- </Viewport3D.Camera>
157
- <ModelVisual3D>
158
- <ModelVisual3D.Content>
159
- <Model3DGroup>
160
- <AmbientLight Color="#ffffff" />
161
- <DirectionalLight Direction="-1,-1,-1" Color="#ffffff" />
162
- </Model3DGroup>
163
- </ModelVisual3D.Content>
164
- </ModelVisual3D>
165
- <local:Sphere3D x:Name="sphere" />
166
- </Viewport3D>
167
-
168
- </Canvas>
169
- </Window>
170
- ```
171
-
172
- ```C#
173
- using System;
174
- using System.Windows;
175
- using System.Windows.Controls;
176
- using System.Windows.Input;
177
- using System.Windows.Media;
178
- using System.Windows.Media.Imaging;
179
- using System.Windows.Media.Media3D;
180
-
181
- namespace Questions228869
182
- {
183
- public partial class MainWindow : Window
184
- {
185
- private readonly RenderTargetBitmap inflateImage;
186
- // 倍率 それっぽくなるように現物合わせ
187
- private const double scale = 0.85;
188
- // 球に巻き始める余白部分 6時が正面とすると3時から反時計回り?
189
- private const double offset = cropWidth / 4 * 3;
190
- // 球に巻く画像の幅 高さから逆算
191
- private const double cropWidth = Math.PI * cropHeight * scale;
192
- // 球に巻く画像の高さ viewport.Height に合わせた 特に根拠なし
193
- private const double cropHeight = 100 * scale;
194
-
195
- public MainWindow()
196
- {
197
- InitializeComponent();
198
-
199
- // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
200
- // 上下右はもっと小さくていいが面倒なので全方向同じ数字で広げた
201
- var image = (BitmapImage)Resources["earthImage"];
202
- var visual = new DrawingVisual();
203
- var dc = visual.RenderOpen();
204
- var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
205
- dc.DrawRectangle(Brushes.White, null, rect);
206
- dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
207
- dc.Close();
208
-
209
- inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
210
- inflateImage.Render(visual);
211
- }
212
-
213
- private void Window_MouseMove(object sender, MouseEventArgs e)
214
- {
215
- var p = e.GetPosition(sourceImage);
216
-
217
- viewport.SetValue(Canvas.LeftProperty, p.X - viewport.Width / 2);
218
- viewport.SetValue(Canvas.TopProperty, p.Y - viewport.Height / 2);
219
-
220
- var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
221
- var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
222
-
223
- var sourceX = ratioX * p.X;
224
- var sourceY = ratioY * p.Y;
225
-
226
- var x = sourceX; // 巻き始め分を大きくしたのでちょうどxで合う
227
- var y = sourceY - cropHeight / 2 + offset;
228
- var rect = new Int32Rect((int)x, (int)y, (int)cropWidth, (int)cropHeight);
229
- try
230
- {
231
- var croppedBitmap = new CroppedBitmap(inflateImage, rect);
232
- sphere.Material = new DiffuseMaterial(new ImageBrush(croppedBitmap));
233
- }
234
- catch { /* NOP CroppedBitmapが範囲外 */ }
235
- }
236
- }
237
- }
238
- ```
239
-
240
- 使用感
241
- * 球なので境目がわかってしまう。
242
- * パフォーマンスはよい(特に間引いていなくても普通に使えてる)
243
- * 大きさの調整等がめんどくさい。
244
- * 凸度?の調整が効かない。
245
- ![イメージ説明](79c4d0cd6210686ff1a91ca34d7179af.png)
246
- ---
247
-
1
+ 少なくともxamlを数行足すって程度では、できそうにもないですね。
2
+ 何かライブラリ等はないかなとも思いましたが、見つけられませんでした。
3
+
4
+ 案1 `OpenCV`的なもので画像を加工して重ねる。
5
+ パフォーマンスもよさそうですし、コード量も少なそう。
6
+ (私は魚眼にする方法は知りません^^;)
7
+
8
+ 案2 球に適当に切り出した画像をマテリアルにマップし続ける。
9
+ 雑に試してみましたが、特に重くはならず使えなくはないって感じでした。
10
+ (自分でもよくわかっていない、雑なC#コードでよければ出せます)
11
+
12
+ 参考コード追記
13
+
14
+ ---
15
+
16
+ 画像を加工パターン
17
+ OpenCVとかわからないですが、GitHubでピュアC#のものを見つけたので試してみました。
18
+ [AnthonyNystrom/GenXSource: Genetibase related source code](https://github.com/AnthonyNystrom/GenXSource) (どういったリポジトリなのか全くわかってません^^;)
19
+
20
+ [IFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/IFilter.cs)
21
+ [EffectFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/EffectFilter.cs)
22
+ [FishEye.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/FishEye.cs)
23
+ 上記3つをプロジェクトに追加(ライセンスが明示されていないので注意してください)
24
+
25
+
26
+ ```xml
27
+ <Window
28
+ x:Class="Questions228869.MainWindow"
29
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
30
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
31
+ Title="Fisheye"
32
+ MouseMove="Window_MouseMove"
33
+ SizeToContent="WidthAndHeight">
34
+ <Window.Resources>
35
+ <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
36
+ </Window.Resources>
37
+
38
+ <Canvas Width="400" Height="300">
39
+ <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
40
+ <Image
41
+ x:Name="zoomImage"
42
+ Width="100"
43
+ Height="100" />
44
+
45
+ </Canvas>
46
+ </Window>
47
+ ```
48
+
49
+ ```cs
50
+ using System;
51
+ using System.Windows;
52
+ using System.Windows.Controls;
53
+ using System.Windows.Input;
54
+ using System.Windows.Media;
55
+ using System.Windows.Media.Imaging;
56
+ using Next2Friends.ImageWorks.EffectsFilters;
57
+
58
+ namespace Questions228869
59
+ {
60
+ public partial class MainWindow : Window
61
+ {
62
+ private readonly RenderTargetBitmap inflateImage;
63
+ private const double offset = 200;
64
+ private int lastTimestamp;
65
+
66
+ public MainWindow()
67
+ {
68
+ InitializeComponent();
69
+
70
+ // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
71
+ var image = (BitmapImage)Resources["earthImage"];
72
+ var visual = new DrawingVisual();
73
+ var dc = visual.RenderOpen();
74
+ var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
75
+ dc.DrawRectangle(Brushes.White, null, rect);
76
+ dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
77
+ dc.Close();
78
+
79
+ inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
80
+ inflateImage.Render(visual);
81
+ }
82
+
83
+ private void Window_MouseMove(object sender, MouseEventArgs e)
84
+ {
85
+ // GCが走り続けて引っかかるので適当に間引く
86
+ if(Math.Abs(e.Timestamp - lastTimestamp) < 20) return;
87
+ lastTimestamp = e.Timestamp;
88
+
89
+ var p = e.GetPosition(sourceImage);
90
+
91
+ zoomImage.SetValue(Canvas.LeftProperty, p.X - zoomImage.Width / 2);
92
+ zoomImage.SetValue(Canvas.TopProperty, p.Y - zoomImage.Height / 2);
93
+
94
+ var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
95
+ var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
96
+
97
+ var sourceX = ratioX * p.X;
98
+ var sourceY = ratioY * p.Y;
99
+
100
+ var w = ratioX * zoomImage.Width;
101
+ var h = ratioY * zoomImage.Height;
102
+ var x = sourceX - w / 2 + offset;
103
+ var y = sourceY - h / 2 + offset;
104
+ var rect = new Int32Rect((int)x, (int)y, (int)w, (int)h);
105
+ try
106
+ {
107
+ var croppedBitmap = new CroppedBitmap(inflateImage, rect);
108
+ zoomImage.Source = new FisheyeFilter(0.1f).ExecuteFilter(croppedBitmap);
109
+ }
110
+ catch { /* NOP CroppedBitmapが範囲外 */ }
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ 使用感
117
+ * 画像を凸に加工しているので境目が見えなくて見た目はよい。
118
+ * GCが走り続けて引っかかるので、適度に間引いたところまあまあ使えるかなと(高速化の余地はまだまだあるので、不満ならどうにかなる)
119
+ * 原寸表示だと1ドットの線とかが荒れがち。
120
+ ![イメージ説明](0d9b8293e9216706e81519b0a5011945.png)
121
+ ---
122
+
123
+
124
+ 球体に貼るパターン
125
+ [WPF で 3D(その5) : リード開発メモ](http://freed411.doorblog.jp/archives/31528830.html)
126
+ 基本的にはここの通り。
127
+ `Primitive3D`と`Sphere3D`をプロジェクトに追加、`GetTextureCoordinate`を修正(元ネタはMicrosoftのサンプル 解凍時に使用許諾が出るので確認してください)
128
+ xamlで書けることはできるだけ移したため、csは跡形ないです。
129
+
130
+ ほか参考にしたサイト [WPF で地球を回してみるテスト - CX's Hatena Blog](http://cx20.hatenablog.com/entry/2014/02/11/215835)
131
+
132
+ ```xml
133
+ <Window
134
+ x:Class="Questions228869.MainWindow"
135
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
136
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
137
+ xmlns:local="clr-namespace:Questions228869"
138
+ Title="Sphere3D"
139
+ MouseMove="Window_MouseMove"
140
+ SizeToContent="WidthAndHeight">
141
+ <Window.Resources>
142
+ <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
143
+ </Window.Resources>
144
+
145
+ <Canvas Width="400" Height="300">
146
+ <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
147
+ <Viewport3D
148
+ x:Name="viewport"
149
+ Width="100"
150
+ Height="100">
151
+ <Viewport3D.Camera>
152
+ <PerspectiveCamera
153
+ LookDirection="0,0,-1"
154
+ Position="0,0,3"
155
+ UpDirection="0,1,0" />
156
+ </Viewport3D.Camera>
157
+ <ModelVisual3D>
158
+ <ModelVisual3D.Content>
159
+ <Model3DGroup>
160
+ <AmbientLight Color="#ffffff" />
161
+ <DirectionalLight Direction="-1,-1,-1" Color="#ffffff" />
162
+ </Model3DGroup>
163
+ </ModelVisual3D.Content>
164
+ </ModelVisual3D>
165
+ <local:Sphere3D x:Name="sphere" />
166
+ </Viewport3D>
167
+
168
+ </Canvas>
169
+ </Window>
170
+ ```
171
+
172
+ ```cs
173
+ using System;
174
+ using System.Windows;
175
+ using System.Windows.Controls;
176
+ using System.Windows.Input;
177
+ using System.Windows.Media;
178
+ using System.Windows.Media.Imaging;
179
+ using System.Windows.Media.Media3D;
180
+
181
+ namespace Questions228869
182
+ {
183
+ public partial class MainWindow : Window
184
+ {
185
+ private readonly RenderTargetBitmap inflateImage;
186
+ // 倍率 それっぽくなるように現物合わせ
187
+ private const double scale = 0.85;
188
+ // 球に巻き始める余白部分 6時が正面とすると3時から反時計回り?
189
+ private const double offset = cropWidth / 4 * 3;
190
+ // 球に巻く画像の幅 高さから逆算
191
+ private const double cropWidth = Math.PI * cropHeight * scale;
192
+ // 球に巻く画像の高さ viewport.Height に合わせた 特に根拠なし
193
+ private const double cropHeight = 100 * scale;
194
+
195
+ public MainWindow()
196
+ {
197
+ InitializeComponent();
198
+
199
+ // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
200
+ // 上下右はもっと小さくていいが面倒なので全方向同じ数字で広げた
201
+ var image = (BitmapImage)Resources["earthImage"];
202
+ var visual = new DrawingVisual();
203
+ var dc = visual.RenderOpen();
204
+ var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
205
+ dc.DrawRectangle(Brushes.White, null, rect);
206
+ dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
207
+ dc.Close();
208
+
209
+ inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
210
+ inflateImage.Render(visual);
211
+ }
212
+
213
+ private void Window_MouseMove(object sender, MouseEventArgs e)
214
+ {
215
+ var p = e.GetPosition(sourceImage);
216
+
217
+ viewport.SetValue(Canvas.LeftProperty, p.X - viewport.Width / 2);
218
+ viewport.SetValue(Canvas.TopProperty, p.Y - viewport.Height / 2);
219
+
220
+ var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
221
+ var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
222
+
223
+ var sourceX = ratioX * p.X;
224
+ var sourceY = ratioY * p.Y;
225
+
226
+ var x = sourceX; // 巻き始め分を大きくしたのでちょうどxで合う
227
+ var y = sourceY - cropHeight / 2 + offset;
228
+ var rect = new Int32Rect((int)x, (int)y, (int)cropWidth, (int)cropHeight);
229
+ try
230
+ {
231
+ var croppedBitmap = new CroppedBitmap(inflateImage, rect);
232
+ sphere.Material = new DiffuseMaterial(new ImageBrush(croppedBitmap));
233
+ }
234
+ catch { /* NOP CroppedBitmapが範囲外 */ }
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ 使用感
241
+ * 球なので境目がわかってしまう。
242
+ * パフォーマンスはよい(特に間引いていなくても普通に使えてる)
243
+ * 大きさの調整等がめんどくさい。
244
+ * 凸度?の調整が効かない。
245
+ ![イメージ説明](79c4d0cd6210686ff1a91ca34d7179af.png)
246
+ ---
247
+
248
248
  使用画像 1280x407 [テイソーの指示楕円-ランベルト正積円筒図法の場合](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png)

1

コード追記

2019/12/14 14:07

投稿

TN8001
TN8001

スコア10108

answer CHANGED
@@ -7,4 +7,242 @@
7
7
 
8
8
  案2 球に適当に切り出した画像をマテリアルにマップし続ける。
9
9
  雑に試してみましたが、特に重くはならず使えなくはないって感じでした。
10
- (自分でもよくわかっていない、雑なC#コードでよければ出せます)
10
+ (自分でもよくわかっていない、雑なC#コードでよければ出せます)
11
+
12
+ 参考コード追記
13
+
14
+ ---
15
+
16
+ 画像を加工パターン
17
+ OpenCVとかわからないですが、GitHubでピュアC#のものを見つけたので試してみました。
18
+ [AnthonyNystrom/GenXSource: Genetibase related source code](https://github.com/AnthonyNystrom/GenXSource) (どういったリポジトリなのか全くわかってません^^;)
19
+
20
+ [IFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/IFilter.cs)
21
+ [EffectFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/EffectFilter.cs)
22
+ [FishEye.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/FishEye.cs)
23
+ 上記3つをプロジェクトに追加(ライセンスが明示されていないので注意してください)
24
+
25
+
26
+ ```xaml
27
+ <Window
28
+ x:Class="Questions228869.MainWindow"
29
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
30
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
31
+ Title="Fisheye"
32
+ MouseMove="Window_MouseMove"
33
+ SizeToContent="WidthAndHeight">
34
+ <Window.Resources>
35
+ <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
36
+ </Window.Resources>
37
+
38
+ <Canvas Width="400" Height="300">
39
+ <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
40
+ <Image
41
+ x:Name="zoomImage"
42
+ Width="100"
43
+ Height="100" />
44
+
45
+ </Canvas>
46
+ </Window>
47
+ ```
48
+
49
+ ```C#
50
+ using System;
51
+ using System.Windows;
52
+ using System.Windows.Controls;
53
+ using System.Windows.Input;
54
+ using System.Windows.Media;
55
+ using System.Windows.Media.Imaging;
56
+ using Next2Friends.ImageWorks.EffectsFilters;
57
+
58
+ namespace Questions228869
59
+ {
60
+ public partial class MainWindow : Window
61
+ {
62
+ private readonly RenderTargetBitmap inflateImage;
63
+ private const double offset = 200;
64
+ private int lastTimestamp;
65
+
66
+ public MainWindow()
67
+ {
68
+ InitializeComponent();
69
+
70
+ // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
71
+ var image = (BitmapImage)Resources["earthImage"];
72
+ var visual = new DrawingVisual();
73
+ var dc = visual.RenderOpen();
74
+ var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
75
+ dc.DrawRectangle(Brushes.White, null, rect);
76
+ dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
77
+ dc.Close();
78
+
79
+ inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
80
+ inflateImage.Render(visual);
81
+ }
82
+
83
+ private void Window_MouseMove(object sender, MouseEventArgs e)
84
+ {
85
+ // GCが走り続けて引っかかるので適当に間引く
86
+ if(Math.Abs(e.Timestamp - lastTimestamp) < 20) return;
87
+ lastTimestamp = e.Timestamp;
88
+
89
+ var p = e.GetPosition(sourceImage);
90
+
91
+ zoomImage.SetValue(Canvas.LeftProperty, p.X - zoomImage.Width / 2);
92
+ zoomImage.SetValue(Canvas.TopProperty, p.Y - zoomImage.Height / 2);
93
+
94
+ var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
95
+ var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
96
+
97
+ var sourceX = ratioX * p.X;
98
+ var sourceY = ratioY * p.Y;
99
+
100
+ var w = ratioX * zoomImage.Width;
101
+ var h = ratioY * zoomImage.Height;
102
+ var x = sourceX - w / 2 + offset;
103
+ var y = sourceY - h / 2 + offset;
104
+ var rect = new Int32Rect((int)x, (int)y, (int)w, (int)h);
105
+ try
106
+ {
107
+ var croppedBitmap = new CroppedBitmap(inflateImage, rect);
108
+ zoomImage.Source = new FisheyeFilter(0.1f).ExecuteFilter(croppedBitmap);
109
+ }
110
+ catch { /* NOP CroppedBitmapが範囲外 */ }
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ 使用感
117
+ * 画像を凸に加工しているので境目が見えなくて見た目はよい。
118
+ * GCが走り続けて引っかかるので、適度に間引いたところまあまあ使えるかなと(高速化の余地はまだまだあるので、不満ならどうにかなる)
119
+ * 原寸表示だと1ドットの線とかが荒れがち。
120
+ ![イメージ説明](0d9b8293e9216706e81519b0a5011945.png)
121
+ ---
122
+
123
+
124
+ 球体に貼るパターン
125
+ [WPF で 3D(その5) : リード開発メモ](http://freed411.doorblog.jp/archives/31528830.html)
126
+ 基本的にはここの通り。
127
+ `Primitive3D`と`Sphere3D`をプロジェクトに追加、`GetTextureCoordinate`を修正(元ネタはMicrosoftのサンプル 解凍時に使用許諾が出るので確認してください)
128
+ xamlで書けることはできるだけ移したため、csは跡形ないです。
129
+
130
+ ほか参考にしたサイト [WPF で地球を回してみるテスト - CX's Hatena Blog](http://cx20.hatenablog.com/entry/2014/02/11/215835)
131
+
132
+ ```xaml
133
+ <Window
134
+ x:Class="Questions228869.MainWindow"
135
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
136
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
137
+ xmlns:local="clr-namespace:Questions228869"
138
+ Title="Sphere3D"
139
+ MouseMove="Window_MouseMove"
140
+ SizeToContent="WidthAndHeight">
141
+ <Window.Resources>
142
+ <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
143
+ </Window.Resources>
144
+
145
+ <Canvas Width="400" Height="300">
146
+ <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
147
+ <Viewport3D
148
+ x:Name="viewport"
149
+ Width="100"
150
+ Height="100">
151
+ <Viewport3D.Camera>
152
+ <PerspectiveCamera
153
+ LookDirection="0,0,-1"
154
+ Position="0,0,3"
155
+ UpDirection="0,1,0" />
156
+ </Viewport3D.Camera>
157
+ <ModelVisual3D>
158
+ <ModelVisual3D.Content>
159
+ <Model3DGroup>
160
+ <AmbientLight Color="#ffffff" />
161
+ <DirectionalLight Direction="-1,-1,-1" Color="#ffffff" />
162
+ </Model3DGroup>
163
+ </ModelVisual3D.Content>
164
+ </ModelVisual3D>
165
+ <local:Sphere3D x:Name="sphere" />
166
+ </Viewport3D>
167
+
168
+ </Canvas>
169
+ </Window>
170
+ ```
171
+
172
+ ```C#
173
+ using System;
174
+ using System.Windows;
175
+ using System.Windows.Controls;
176
+ using System.Windows.Input;
177
+ using System.Windows.Media;
178
+ using System.Windows.Media.Imaging;
179
+ using System.Windows.Media.Media3D;
180
+
181
+ namespace Questions228869
182
+ {
183
+ public partial class MainWindow : Window
184
+ {
185
+ private readonly RenderTargetBitmap inflateImage;
186
+ // 倍率 それっぽくなるように現物合わせ
187
+ private const double scale = 0.85;
188
+ // 球に巻き始める余白部分 6時が正面とすると3時から反時計回り?
189
+ private const double offset = cropWidth / 4 * 3;
190
+ // 球に巻く画像の幅 高さから逆算
191
+ private const double cropWidth = Math.PI * cropHeight * scale;
192
+ // 球に巻く画像の高さ viewport.Height に合わせた 特に根拠なし
193
+ private const double cropHeight = 100 * scale;
194
+
195
+ public MainWindow()
196
+ {
197
+ InitializeComponent();
198
+
199
+ // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
200
+ // 上下右はもっと小さくていいが面倒なので全方向同じ数字で広げた
201
+ var image = (BitmapImage)Resources["earthImage"];
202
+ var visual = new DrawingVisual();
203
+ var dc = visual.RenderOpen();
204
+ var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
205
+ dc.DrawRectangle(Brushes.White, null, rect);
206
+ dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
207
+ dc.Close();
208
+
209
+ inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
210
+ inflateImage.Render(visual);
211
+ }
212
+
213
+ private void Window_MouseMove(object sender, MouseEventArgs e)
214
+ {
215
+ var p = e.GetPosition(sourceImage);
216
+
217
+ viewport.SetValue(Canvas.LeftProperty, p.X - viewport.Width / 2);
218
+ viewport.SetValue(Canvas.TopProperty, p.Y - viewport.Height / 2);
219
+
220
+ var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
221
+ var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
222
+
223
+ var sourceX = ratioX * p.X;
224
+ var sourceY = ratioY * p.Y;
225
+
226
+ var x = sourceX; // 巻き始め分を大きくしたのでちょうどxで合う
227
+ var y = sourceY - cropHeight / 2 + offset;
228
+ var rect = new Int32Rect((int)x, (int)y, (int)cropWidth, (int)cropHeight);
229
+ try
230
+ {
231
+ var croppedBitmap = new CroppedBitmap(inflateImage, rect);
232
+ sphere.Material = new DiffuseMaterial(new ImageBrush(croppedBitmap));
233
+ }
234
+ catch { /* NOP CroppedBitmapが範囲外 */ }
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ 使用感
241
+ * 球なので境目がわかってしまう。
242
+ * パフォーマンスはよい(特に間引いていなくても普通に使えてる)
243
+ * 大きさの調整等がめんどくさい。
244
+ * 凸度?の調整が効かない。
245
+ ![イメージ説明](79c4d0cd6210686ff1a91ca34d7179af.png)
246
+ ---
247
+
248
+ 使用画像 1280x407 [テイソーの指示楕円-ランベルト正積円筒図法の場合](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png)