【慧游魯博】【11】小程序端·游覽畫卷修改·支持圖片url格式·結合圖床上傳和加載·數據對接

文章目錄

  • 需求
  • 修改細節
    • 前端
      • 主要修改點說明:
      • 前端傳遞格式
    • 后端
      • ArtifactItem 類:
      • ScrollServiceImpl 類:
      • 修改 `InfoPanel` 結構
      • 重構 `ScrollHorizontalRollComposer`
      • 修改后的 `ScrollHorizontalRollComposer`
      • 移除冗余代碼
      • 修改總結
    • 數據流
    • 圖片格式兼容性問題
  • 成果展示

需求

由于圖片和文字交流是相互獨立的,故僅保留文字交互信息,然后根據文字中心詞,匹配圖床上的相應url,進行游覽畫卷構建

  1. 數據結構:前端傳遞給后端的是一個對象數組,每個對象包含:
    • description:文物/展品的文字描述(如"陶瓷"、“青銅器”)
    • imageUrl:與該描述對應的默認圖片URL(如陶瓷描述對應陶瓷圖片URL)
  2. 后端處理
    • 接收包含descriptionimageUrl的對象數組
    • 對每個對象:
      • 獲取imageUrl對應的圖片
      • 將圖片和描述組合顯示在畫卷的同一個面板中(圖片上方/下方顯示對應文字)
  3. 展示效果:最終生成的畫卷中,每個文物/展品都是一個圖文結合的面板,而不是圖片和文字分離顯示

修改細節

前端

generateScroll()

async generateScroll() {try {// 禁用按鈕防止重復點擊this.generating = true;uni.showLoading({ title: '生成中...', mask: true });// 構建記錄數據 - 只處理文字類型const records = this.interactionRecords.filter(record => record.type === 'text') // 只保留文字類型記錄.map(record => ({type: 'text', // 強制設置為text類型content: record.content, // 文字內容imageUrl: this.getDefaultImageForText(record.content) // 根據內容匹配默認圖片}));console.log('發送給后端的記錄數據:', JSON.stringify(records, null, 2));// 調用后端接口const res = await post('/api/scroll/generate', records);if (!res) {throw new Error('未獲取到有效響應');}// 預覽生成的畫卷uni.previewImage({current: res,urls: [res],success: () => {// 記錄生成歷史this.interactionRecords.push({type: 'scroll',content: '生成游覽畫卷',imageUrl: res,timestamp: new Date().getTime(),});},fail: (err) => {throw new Error('圖片預覽失敗: ' + (err.errMsg || '未知錯誤'));},});} catch (error) {console.error('生成失敗:', error);uni.showToast({title: '生成失敗: ' + (error.message || '請稍后重試'),icon: 'none',duration: 2000,});} finally {this.generating = false;uni.hideLoading();}
},// 根據文本內容返回匹配的默認圖片URL
getDefaultImageForText(text) {const defaultImages = {'佛像': 'https://i.ibb.co/fGH1bnHs/OIP-C-1.webp','佛教': 'https://i.ibb.co/fGH1bnHs/OIP-C-1.webp','陶瓷': 'https://i.ibb.co/R4kywTQs/OIP-C.webp','青銅器': 'https://i.ibb.co/fV1xCcYd/25bb-hyrtarw2279586.jpg','書畫': 'https://example.com/default-painting.jpg', // 替換為實際URL'文物': 'https://example.com/default-artifact.jpg' // 替換為實際URL};// 查找匹配的關鍵詞const matchedKey = Object.keys(defaultImages).find(key => text.includes(key));// 返回匹配的圖片URL或默認URLreturn matchedKey ? defaultImages[matchedKey] : 'https://example.com/default-museum.jpg';
}

主要修改點說明:

  1. 過濾非文字類型記錄
    • 使用filter(record => record.type === 'text')只保留文字類型的交互記錄
  2. 統一數據結構
    • 所有記錄都設置為type: 'text'
    • content字段包含原始文字內容
    • imageUrl字段根據文字內容自動匹配默認圖片
  3. 改進圖片匹配邏輯
    • 使用對象映射方式匹配關鍵詞和圖片URL
    • 支持多個關鍵詞匹配同一圖片(如"佛像"和"佛教")
    • 提供默認圖片URL作為后備
  4. 增強日志輸出
    • 在發送請求前打印完整的數據結構,便于調試
  5. 錯誤處理
    • 保留原有的錯誤處理邏輯,確保用戶體驗

前端傳遞格式

[{"type": "text","content": "這是第一段文字","imageUrl": "https://example.com/background1.jpg"},{"type": "text","content": "這是第二段文字","imageUrl": "https://example.com/background2.jpg"}
]

后端

ArtifactItem 類:

  • 當前設計同時支持圖片和文字類型,但如果只接受文字類型,可以簡化這個類
  • 可以移除 type 字段和 imageUrl 字段,因為不再需要區分類型
public class ArtifactItem {private String content; // 只需要保留文字內容public String getContent() {return content;}public void setContent(String content) {this.content = content;}
}

ScrollServiceImpl 類:

  • generate() 方法中的處理邏輯可以簡化,因為不再需要處理圖片類型
  • 移除圖片下載相關代碼(因為現在傳遞的是圖片url,而不是圖片格式)
  • 背景生成也需要調整
@Override
public String generate(List<ArtifactItem> records) throws Exception {List<InfoPanel> panels = new ArrayList<>();// 1. 生成背景(可選,如果仍需動態背景)BufferedImage bg = generateNewBackground();BufferedImage frame = loadResourceImage(FRAME_IMAGE_PATH);// 2. 直接使用前端傳遞的 imageUrlfor (ArtifactItem record : records) {if ("text".equals(record.getType())) {panels.add(new InfoPanel(record.getImageUrl(), record.getContent()));}}// 3. 修改 ScrollHorizontalRollComposer.compose() 方法//    現在它需要處理 URL 而不是 BufferedImageBufferedImage content = ScrollHorizontalRollComposer.compose(bg, panels);BufferedImage finalRoll = ScrollFramer.embed(content, frame);// 其余代碼保持不變...return uploadToImageHost(finalRoll);
}

修改 InfoPanel 結構

  • BufferedImage image 改為 String imageUrl
package com.museum.pojo;/** 拼畫卷時用的“小面板”包裝類 */
public class InfoPanel {private String imageUrl; // 改為存儲圖片URLprivate String text;public InfoPanel(String imageUrl, String text) {this.imageUrl = imageUrl;this.text = text;}public String getImageUrl() { return imageUrl; }public String getText() { return text; }
}

重構 ScrollHorizontalRollComposer

  • 動態加載圖片(URLImageLoader.load())。
  • 添加圖片加載失敗的降級處理(占位圖)。
package com.museum.utils;import com.museum.pojo.InfoPanel;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class ScrollHorizontalRollComposer {// 配置參數(保持不變)private static final int PANEL_WIDTH = 560;private static final int PANEL_HEIGHT = 400;private static final int PANEL_VGAP = 50;private static final int TOP_PADDING = 30;private static final int BOTTOM_PADDING = 30;private static final int CARD_MARGIN = 30;private static final int CARD_ROUND = 25;private static final int CARD_ALPHA = 190;private static final int ZIGZAG_OFFSET = 40;private static final int TEXT_PADDING = 40;private static final int FONT_SIZE = 22;private static final int IMAGE_SIZE = 180;// HTTP客戶端(用于動態加載圖片)private static final OkHttpClient httpClient = new OkHttpClient();public static BufferedImage compose(BufferedImage bg, List<InfoPanel> panels) {int panelCount = panels.size();int totalHeight = TOP_PADDING + BOTTOM_PADDING + panelCount * PANEL_HEIGHT + (panelCount - 1) * PANEL_VGAP;BufferedImage scroll = new BufferedImage(PANEL_WIDTH, totalHeight, BufferedImage.TYPE_INT_ARGB);Graphics2D g = scroll.createGraphics();// 1. 繪制背景(平鋪)for (int y = 0; y < totalHeight; y += bg.getHeight()) {g.drawImage(bg, 0, y, PANEL_WIDTH, bg.getHeight(), null);}// 2. 設置字體和抗鋸齒g.setFont(new Font("Serif", Font.PLAIN, FONT_SIZE));g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);FontMetrics fm = g.getFontMetrics();int lineHeight = fm.getHeight();// 3. 繪制每個面板int cursorY = TOP_PADDING;List<Point> centers = new ArrayList<>();for (int i = 0; i < panelCount; i++) {InfoPanel panel = panels.get(i);String[] txtLines = panel.getText().split("(?<=\\。)");// 3.1 計算面板位置(Z字型布局)int cardWidth = PANEL_WIDTH - 2 * CARD_MARGIN;int offsetX = (i % 2 == 0) ? ZIGZAG_OFFSET : -ZIGZAG_OFFSET;int cardX = (PANEL_WIDTH - cardWidth) / 2 + offsetX;// 3.2 繪制陰影和卡片背景g.setColor(new Color(0, 0, 0, 28));g.fillRoundRect(cardX + 5, cursorY + 5, cardWidth, PANEL_HEIGHT, CARD_ROUND, CARD_ROUND);g.setColor(new Color(255, 255, 255, CARD_ALPHA));g.fillRoundRect(cardX, cursorY, cardWidth, PANEL_HEIGHT, CARD_ROUND, CARD_ROUND);// 3.3 動態加載并繪制圖片(關鍵修改點)try {BufferedImage img = loadImageFromUrl(panel.getImageUrl());int imgX = cardX + (cardWidth - IMAGE_SIZE) / 2;int imgY = cursorY + 30;g.drawImage(img, imgX, imgY, IMAGE_SIZE, IMAGE_SIZE, null);} catch (IOException e) {// 圖片加載失敗時繪制占位符g.setColor(Color.LIGHT_GRAY);g.fillRect(cardX + (cardWidth - IMAGE_SIZE)/2, cursorY + 30, IMAGE_SIZE, IMAGE_SIZE);g.setColor(Color.RED);g.drawString("圖片加載失敗", cardX + 20, cursorY + 60);}// 3.4 繪制文字g.setColor(Color.BLACK);int textX = cardX + TEXT_PADDING;int textY = cursorY + 30 + IMAGE_SIZE + 30;int textMaxWidth = cardWidth - 2 * TEXT_PADDING;drawWrappedText(g, txtLines, textX, textY, textMaxWidth, lineHeight);// 記錄面板中心點(用于后續繪制連接線)centers.add(new Point(cardX + cardWidth/2, cursorY + PANEL_HEIGHT/2));cursorY += PANEL_HEIGHT + PANEL_VGAP;}// 4. 繪制面板間的連接線(保持不變)drawConnectingLines(g, centers);g.dispose();return scroll;}// 新增方法:從URL加載圖片private static BufferedImage loadImageFromUrl(String imageUrl) throws IOException {Request request = new Request.Builder().url(imageUrl).build();try (Response response = httpClient.newCall(request).execute()) {if (!response.isSuccessful() || response.body() == null) {throw new IOException("HTTP " + response.code());}return ImageIO.read(response.body().byteStream());}}// 繪制連接線(保持不變)private static void drawConnectingLines(Graphics2D g, List<Point> centers) {g.setColor(new Color(90, 90, 90, 180));float[] dash = {10, 5};g.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10f, dash, 0));for (int i = 0; i < centers.size() - 1; i++) {Point p1 = centers.get(i);Point p2 = centers.get(i + 1);int ctrlY = (p1.y + p2.y)/2 + 60 * ((i%2 == 0) ? 1 : -1);CubicCurve2D curve = new CubicCurve2D.Float(p1.x, p1.y, p1.x, ctrlY, p2.x, ctrlY, p2.x, p2.y);g.draw(curve);}}// 文字換行處理(優化版)private static void drawWrappedText(Graphics2D g, String[] lines, int x, int y, int maxWidth, int lineHeight) {FontMetrics fm = g.getFontMetrics();for (String line : lines) {if (fm.stringWidth(line) <= maxWidth) {g.drawString(line, x, y);y += lineHeight;} else {// 處理長文本換行StringBuilder currentLine = new StringBuilder();for (char c : line.toCharArray()) {if (fm.stringWidth(currentLine.toString() + c) > maxWidth) {g.drawString(currentLine.toString(), x, y);y += lineHeight;currentLine.setLength(0);}currentLine.append(c);}if (currentLine.length() > 0) {g.drawString(currentLine.toString(), x, y);y += lineHeight;}}}}
}

修改后的 ScrollHorizontalRollComposer

InfoPanel 改為存儲圖片 URL 而非 BufferedImage,需要重構 ScrollHorizontalRollComposer

package com.museum.utils;import com.museum.pojo.InfoPanel;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class ScrollHorizontalRollComposer {// 配置參數(保持不變)private static final int PANEL_WIDTH = 560;private static final int PANEL_HEIGHT = 400;private static final int PANEL_VGAP = 50;private static final int TOP_PADDING = 30;private static final int BOTTOM_PADDING = 30;private static final int CARD_MARGIN = 30;private static final int CARD_ROUND = 25;private static final int CARD_ALPHA = 190;private static final int ZIGZAG_OFFSET = 40;private static final int TEXT_PADDING = 40;private static final int FONT_SIZE = 22;private static final int IMAGE_SIZE = 180;// HTTP客戶端(用于動態加載圖片)private static final OkHttpClient httpClient = new OkHttpClient();public static BufferedImage compose(BufferedImage bg, List<InfoPanel> panels) {int panelCount = panels.size();int totalHeight = TOP_PADDING + BOTTOM_PADDING + panelCount * PANEL_HEIGHT + (panelCount - 1) * PANEL_VGAP;BufferedImage scroll = new BufferedImage(PANEL_WIDTH, totalHeight, BufferedImage.TYPE_INT_ARGB);Graphics2D g = scroll.createGraphics();// 1. 繪制背景(平鋪)for (int y = 0; y < totalHeight; y += bg.getHeight()) {g.drawImage(bg, 0, y, PANEL_WIDTH, bg.getHeight(), null);}// 2. 設置字體和抗鋸齒g.setFont(new Font("Serif", Font.PLAIN, FONT_SIZE));g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);FontMetrics fm = g.getFontMetrics();int lineHeight = fm.getHeight();// 3. 繪制每個面板int cursorY = TOP_PADDING;List<Point> centers = new ArrayList<>();for (int i = 0; i < panelCount; i++) {InfoPanel panel = panels.get(i);String[] txtLines = panel.getText().split("(?<=\\。)");// 3.1 計算面板位置(Z字型布局)int cardWidth = PANEL_WIDTH - 2 * CARD_MARGIN;int offsetX = (i % 2 == 0) ? ZIGZAG_OFFSET : -ZIGZAG_OFFSET;int cardX = (PANEL_WIDTH - cardWidth) / 2 + offsetX;// 3.2 繪制陰影和卡片背景g.setColor(new Color(0, 0, 0, 28));g.fillRoundRect(cardX + 5, cursorY + 5, cardWidth, PANEL_HEIGHT, CARD_ROUND, CARD_ROUND);g.setColor(new Color(255, 255, 255, CARD_ALPHA));g.fillRoundRect(cardX, cursorY, cardWidth, PANEL_HEIGHT, CARD_ROUND, CARD_ROUND);// 3.3 動態加載并繪制圖片(關鍵修改點)try {BufferedImage img = loadImageFromUrl(panel.getImageUrl());int imgX = cardX + (cardWidth - IMAGE_SIZE) / 2;int imgY = cursorY + 30;g.drawImage(img, imgX, imgY, IMAGE_SIZE, IMAGE_SIZE, null);} catch (IOException e) {// 圖片加載失敗時繪制占位符g.setColor(Color.LIGHT_GRAY);g.fillRect(cardX + (cardWidth - IMAGE_SIZE)/2, cursorY + 30, IMAGE_SIZE, IMAGE_SIZE);g.setColor(Color.RED);g.drawString("圖片加載失敗", cardX + 20, cursorY + 60);}// 3.4 繪制文字g.setColor(Color.BLACK);int textX = cardX + TEXT_PADDING;int textY = cursorY + 30 + IMAGE_SIZE + 30;int textMaxWidth = cardWidth - 2 * TEXT_PADDING;drawWrappedText(g, txtLines, textX, textY, textMaxWidth, lineHeight);// 記錄面板中心點(用于后續繪制連接線)centers.add(new Point(cardX + cardWidth/2, cursorY + PANEL_HEIGHT/2));cursorY += PANEL_HEIGHT + PANEL_VGAP;}// 4. 繪制面板間的連接線(保持不變)drawConnectingLines(g, centers);g.dispose();return scroll;}// 新增方法:從URL加載圖片private static BufferedImage loadImageFromUrl(String imageUrl) throws IOException {Request request = new Request.Builder().url(imageUrl).build();try (Response response = httpClient.newCall(request).execute()) {if (!response.isSuccessful() || response.body() == null) {throw new IOException("HTTP " + response.code());}return ImageIO.read(response.body().byteStream());}}// 繪制連接線(保持不變)private static void drawConnectingLines(Graphics2D g, List<Point> centers) {g.setColor(new Color(90, 90, 90, 180));float[] dash = {10, 5};g.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10f, dash, 0));for (int i = 0; i < centers.size() - 1; i++) {Point p1 = centers.get(i);Point p2 = centers.get(i + 1);int ctrlY = (p1.y + p2.y)/2 + 60 * ((i%2 == 0) ? 1 : -1);CubicCurve2D curve = new CubicCurve2D.Float(p1.x, p1.y, p1.x, ctrlY, p2.x, ctrlY, p2.x, p2.y);g.draw(curve);}}// 文字換行處理(優化版)private static void drawWrappedText(Graphics2D g, String[] lines, int x, int y, int maxWidth, int lineHeight) {FontMetrics fm = g.getFontMetrics();for (String line : lines) {if (fm.stringWidth(line) <= maxWidth) {g.drawString(line, x, y);y += lineHeight;} else {// 處理長文本換行StringBuilder currentLine = new StringBuilder();for (char c : line.toCharArray()) {if (fm.stringWidth(currentLine.toString() + c) > maxWidth) {g.drawString(currentLine.toString(), x, y);y += lineHeight;currentLine.setLength(0);}currentLine.append(c);}if (currentLine.length() > 0) {g.drawString(currentLine.toString(), x, y);y += lineHeight;}}}}
}

關鍵修改說明

  1. 圖片加載方式
    • 移除對 InfoPanel.getImage() 的依賴
    • 新增 loadImageFromUrl() 方法,通過 HTTP 動態加載圖片
    • 添加圖片加載失敗時的降級處理(顯示占位符)
  2. 性能優化
    • 使用靜態 OkHttpClient 復用連接
    • 圖片按需加載,避免預先下載所有圖片
  3. 錯誤處理
    • 捕獲 IOException 并顯示錯誤提示
    • 保持畫卷生成流程不被單張圖片失敗中斷
  4. 兼容性
    • 完全適配修改后的 InfoPanel 結構(imageUrl + text
    • 保留原有布局和樣式邏輯

移除冗余代碼

刪除 ImageCropper 和本地圖片裁剪邏輯。

修改總結

文件原版本(本地文件)修改版本(URL處理)主要改動點
ScrollHorizontalRollComposer直接使用BufferedImagepanels.get(i).getImage()新增loadImageFromUrl()方法: java<br>BufferedImage img = loadImageFromUrl(panel.getImageUrl());<br> 支持HTTP下載圖片,失敗時顯示占位符1. 通過URL動態加載圖片 2. 使用OkHttpClient 3. 錯誤降級處理
ImageCropper僅支持文件路徑輸入: ImageIO.read(new File(path))支持兩種輸入方式: java<br>// 方式1:URL轉臨時文件<br>crop(downloadToTemp(url), w, h);<br><br>// 方式2:直接處理BufferedImage<br>crop(bufferedImage, w, h);<br>1. 增加日志 2. 支持內存圖像處理 3. 優化縮放插值
ScrollService處理MultipartFile上傳: java<br>multipartFile.transferTo(tempFile);<br>cropImageFile(tempFile...);<br>完全重構為URL處理: java<br>// 動態生成背景圖<br>BufferedImage bg = generateNewBackground();<br><br>// 直接使用URL創建面板<br>panels.add(new InfoPanel(url, text));<br><br>// 自動上傳結果到圖床<br>uploadScrollToImageHost(finalRoll);<br>1. 移除文件上傳邏輯 2. 新增DALL-E背景生成 3. 集成圖床自動上傳
InfoPanel模型存儲BufferedImagejava<br>private BufferedImage image;<br>改為存儲圖片URL: java<br>private String imageUrl; // 存儲URL<br>模型層解耦圖像存儲
ScrollFramer簡單居中嵌入: java<br>g.drawImage(content, x, y, null);<br>智能縮放+裁剪: java<br>// 計算縮放比例<br>double scale = innerH / content.getHeight();<br><br>// 水平居中裁剪<br>if (cropX > 0) {<br> content.getSubimage(cropX, 0, w, h);<br>}<br>1. 自適應內容尺寸 2. 精確邊框對齊

數據流

前端 后端 圖床 [{content:"青銅器", imageUrl:"..."},...] 下載圖片 合成畫卷 上傳結果 返回畫卷URL 前端 后端 圖床

圖片格式兼容性問題

  • 使用的圖片是 .webp 格式,但 Java 原生 ImageIO 不支持 WebP。
  • 錯誤日志中 BufferedImage.getWidth() failed 表明圖片已下載但無法解析。

解決方案

引入 WebP 支持庫

<dependency><groupId>com.twelvemonkeys.imageio</groupId><artifactId>imageio-webp</artifactId><version>3.9.4</version>
</dependency>

同時,上傳的圖床的照片格式盡量使jpg

成果展示

測試版

在這里插入圖片描述

最終版

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909935.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909935.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909935.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

攻克SQL審核“最后堡壘”!PawSQL首發T-SQL存儲過程深度優化引擎

為什么存儲過程審核那么難&#xff1f; 存儲過程將數據操作邏輯固化在數據庫層&#xff0c;一次編譯、多次執行&#xff0c;既能大幅提升性能&#xff0c;也能通過權限隔離增強安全。然而&#xff0c;正因其邏輯復雜、分支眾多&#xff0c;存儲過程內部的 SQL 審核與優化常常成…

計算機網絡零基礎完全指南

目錄 ?? 什么是計算機網絡 生活中的類比 計算機網絡的本質 網絡的發展歷程 ?? 網絡IP詳解(重點) 1. IP地址是什么? 生活例子:IP地址就像門牌號 IP地址的格式 IP地址的二進制表示 2. IP地址的分類詳解 A類地址(大型網絡) B類地址(中型網絡) C類地址(小…

DL___線性神經網絡

1&#xff09;回歸&#xff08;regression&#xff09;是能為一個或多個自變量與因變量之間關系建模的一類方法。 在自然科學和社會科學領域&#xff0c;回歸經常用來表示輸入和輸出之間的關系。 2&#xff09;一般回歸是和預測有關&#xff0c;比如預測價格(房屋&#xff0c;…

WSL2安裝與使用(USB、GPU、虛擬機、圖形界面)

文章目錄 前言WSL2安裝&#xff08;手動安裝&#xff09;WSL2基礎使用VS Code與WSL2配合使用連接USB設備WSL2中使用GPU&#xff08;RTX5060Ti 16G&#xff09;與虛擬機兼容使用&#xff08;Virtual Box&#xff09;圖形與桌面環境WSL消失&#xff08;災難性故障&#xff09;問題…

uni-app項目實戰筆記16--實現頭部導航欄效果

先來看效果&#xff1a; 要求&#xff1a;頂部導航欄要始終固定在上方&#xff0c;不隨頁面上下拖動而消失。 代碼實現&#xff1a; 1.定義一個自定義導航欄組件&#xff1a;custom-nav-bar.vue&#xff0c;并寫入如下代碼&#xff1a; <template><view class"…

web3.js 核心包及子模塊

. 核心包 (web3) 功能:提供基礎連接、工具函數和核心功能。 包含子模塊: web3.eth - 以太坊區塊鏈交互 web3.utils - 輔助工具函數 web3.shh - Whisper 協議(已廢棄) web3.bzz - Swarm 去中心化存儲(已廢棄) web3.net - 網絡相關功能 web3.contract - 智能合約交互 web3.…

訓練檢測之前的視頻抽幀

接下來安裝pytorch Previous PyTorch Versions 視頻抽幀 import cv2def extract_frames(video_path, output_folder, frame_rate1):"""從視頻中抽取幀。:param video_path: 視頻文件的路徑:param output_folder: 存儲幀的文件夾路徑:param frame_rate: 抽取的…

智能家居HA篇 二、配置Home Assistant并實現外部訪問

智能家居HA篇 一、Win10 VM虛擬機安裝 Home Assistant 手把手教學 二、通過Cpolar配置Home Assistant并實現外部訪問 文章目錄 智能家居HA篇前言一、內網穿透工具&#xff08;cpolar&#xff09;二、映射HA端口1.訪問cpolar儀表2.創建賬號并登錄3.創建隧道 三、HA設置及公網訪…

day09——Java基礎項目(ATM系統)

文章目錄 Java項目實戰&#xff1a;手把手開發ATM銀行系統&#xff08;附完整源碼&#xff09;一、系統架構設計1. 三層架構模型2. 核心數據結構 二、核心功能實現1. 開戶功能&#xff08;含唯一卡號生成&#xff09;2. 登錄安全驗證3. 存取款業務4. 安全轉賬實現 三、賬戶安全…

計算機網絡:(五)信道復用技術,數字傳輸系統,寬帶接入技術

計算機網絡&#xff1a;&#xff08;五&#xff09;信道復用技術&#xff0c;數字傳輸系統&#xff0c;寬帶接入技術 前言一、信道復用技術1. 為什么需要復用技術&#xff1f;2. 頻分復用&#xff08;FDM&#xff09;3. 時分復用&#xff08;TDM&#xff09;4. 統計時分復用&am…

【期末總結】計算機網絡

【期末總結】計算機網絡 參考鏈接&#xff1a;計算機網絡知識點全面總結&#xff08;有這一篇就夠了&#xff01;&#xff01;&#xff01;&#xff09;-CSDN博客 一.概述 1.1 計算機網絡的分類 按照網絡的作用范圍&#xff1a;廣域網&#xff08;WAN&#xff09;、城域網&a…

React學習001-創建 React 應用

React學習001-創建 React 應用 1、安裝node.js2、安裝構建工具2.1 核心特性2.2 性能對比??2.3 適用場景?? 3、創建應用4、項目啟動參考文章 1、安裝node.js 這里建議安裝nvm多版本管理node.js&#xff0c;想用哪個版本&#xff0c;一條命令即可~ 多版本管理node.js 2、安…

(cvpr2025) Adaptive Rectangular Convolution for Remote Sensing Pansharpening

論文&#xff1a;(cvpr2025) Adaptive Rectangular Convolution for Remote Sensing Pansharpening 代碼&#xff1a;https://github.com/WangXueyang-uestc/ARConv.git 這個論文研究的是全色與多光譜圖像的融合。作者認為現有的基于CNN的方法中&#xff0c;傳統的卷積存在兩個…

【圖像處理入門】7. 特征描述子:從LBP到HOG的特征提取之道

摘要 特征描述子是圖像處理中提取圖像本質信息的關鍵工具。本文將深入講解局部二值模式(LBP)與方向梯度直方圖(HOG)兩種經典特征描述子的原理、實現方法及應用場景。結合OpenCV代碼示例,展示如何利用LBP提取紋理特征、使用HOG進行目標檢測,幫助讀者掌握從圖像中提取有效…

AI 應用開發的‘核心樞紐’:Dify、Coze、n8n、FastGPT、MaxKB、RAGFlow 等六大平臺全面對決

在人工智能與自動化流程日益普及的當下&#xff0c;各類平臺如雨后春筍般涌現&#xff0c;成為構建智能應用與自動化工作流的 “核心樞紐”。其中&#xff0c;Dify、Coze、n8n、FastGPT、MaxKB、RAGFlow 備受矚目&#xff0c;它們各自具備獨特的功能與優勢&#xff0c;適用于不…

RV1126+OPENCV對視頻流單獨進行視頻膨脹/腐蝕操作

一.RV1126OPENCV對視頻流進行視頻膨脹操作的大體流程圖 思路&#xff1a;初始化VI與VENC模塊&#xff0c;之后開啟兩個線程&#xff0c;一個線程從VI模塊獲取視頻流數據&#xff0c;用Opencv的Mat將其轉成Mat矩陣之后進行用dilate膨脹&#xff0c;將膨脹之后的視頻數據用send函…

Cordova + Vue 移動端視頻播放組件(支持 HLS + 原生播放器兜底)

在混合 App 中&#xff0c;移動端使用 標簽播放視頻經常踩坑&#xff0c;尤其是格式兼容、跨域限制、WebView 差異等問題。 本文介紹一個通用的 Cordova 視頻播放組件&#xff1a;優先 HTML5 播放&#xff0c;播放失敗自動提示用戶使用系統播放器&#xff0c;并支持原生插件兜底…

【Linux】掌握vim編譯器使用——詳細教程

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 一、Vim的三種核心模式解析 二、高效編輯核心命令大全 1. 光標快速導航 2. 文本編輯四連擊 3. 高效搜索替換 三、Vim神技&#xff1a;批量注釋與多文件編輯 1. 批量…

Oracle遷移瀚高,如何做表等對象與文件名一對一的文件腳本(APP)

文章目錄 環境文檔用途詳細信息 環境 系統平臺&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;4.5 文檔用途 Oracle遷移到瀚高后&#xff0c;需要整理一張表對應一個與表同名的腳本&#xff0c;一個函數對應一個與函數同名的腳本 詳細信息 一、整理…